I see a piece of code similar to the one below in some npm package:
this.func(callback).then(function() {
...
return x;
}).then(function() {
...
return y;
}).then(function() {
...
return z;
}).then(function() {
mocha.run(function(failures) {
...
callback(failures);
});
}).catch(callback);
Questions:
What is the meaning of this catch(callback) with no {...} block following it?
I would like to add a finally clause to execute the callback, but every syntax that I'm trying seems to fail:
.catch(callback).finally(callback);
.catch(callback).finally(callback());
.catch(callback).finally{callback()};
.catch(callback).finally(){callback()};
In your case, then and catch refer to Promise's prototype and not to the native catch implementation. Check this example to understand it better:
let doSomething = () {
return new Promise((resolve, reject) => {
try {
reject();
} catch(e) {
reject();
} finally {
console.log('done');
}
});
}
doSomething().then(() => {}).catch(() => {});
Note that anything you'd do, catch will be called.
In your case catch function refers to your callback function which you are passing in catch block
//first case
function callback(){}
catch(callback);
//second case
catch(function(){})
Both case will work
and for finally It is still lacking browser support, you can check here at bottom of this page
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally
and check this for how to do finally in alternative way.
what is the equivalent of bluebird Promise.finally in native ES6 promises?
you can try like this.
For more detail on promise: see here
doSomething(()=>{//do something})
.then(()=>{})
.catch((error)=> { console.log(error); })
.finally(()=> { //finally block here });
Question 1: The Promise API calls the function passed in the catch whenever a promise gets "rejected". So consider the following code:
// method 1: define the callback function
var callback = function(error){
console.error(error); // console the error
};
this.func.then(...).catch(callback);
// method 2: pass the function assigned to "callback" variable itself
this.func.then(...).catch(function(error){
console.error(error); // console the error
});
You are just telling the promise returned by the above (in your code) function call(s) that:
"Hey, whenever you fail to do the task, call this function callback that I (or someone else) have defined."
Question 2: The first method in your list of four methods should work.
Related
Basically Visual Studio Code gives me the note 'await' has no effect on the type of this expression. but I am note able to track the actual problem down. Of course my example here is a bit nested and therefor a bit more complex than it maybe has to be. It all starts with an array where I want to check it a value is valid. If on value fails the test, the .every function should end.
myList.every(function (value) {
if(value == null) return false;
//other stuff for preparation
return _handleValue(value);
});
value is a complex datatype so the _handleValue function is splitted into different subfunctions. Some of the function are using promises some (atm) don't. Please ignore the functions in the if block because the code is simplified and this is not causing the problem.
async function _handleValue(value) {
if (somePreChecks(value)) {
return false;
}
else if (valueIsType(value)) {
return await _someHandlerwithPromise(value); //<-- Using await here.
} else if (valueIsOtherType(value)) {
return _someOtherHandlerWithoutPromise(value);
}
}
The function _someHandlerWithPromise has some call which are using callback. Anyway this should not be a problem as long as I call reject().
function _someHandlerWithPromise(value) {
return new Promise(resolve => {
foo.acceptValue(value, function (data) {
_updateSystem(data, function (err, data) {
if(err){
//Do something
}
resolve(true);
});
});
});
}
Actually this worked pretty well elsewhere where I do not use the await function. But because the .every is not able to handle asynchronous methods, I am forced to use await.
Please see this minimum example:
I have data like this:
const testObject = { test: 'foo' };
And my main function is this:
Cause error
// This cause error
function handleResponse(response) {
return response.json().then(Promise.reject); // Please notice this line
}
try {
await handleResponse({
json: () => Promise.resolve(testObject),
});
} catch (err) {
console.log(err);
// => TypeError: PromiseReject called on non-object
}
And this one works:
Correct
// This works
function handleResponse(response) {
return response.json().then((res) => Promise.reject(res)); // Please notice this line
}
try {
await handleResponse({
json: () => Promise.resolve(testObject),
});
} catch (err) {
console.log(err);
// => {test: "foo"}
}
Why is this happening? What did I missing?
something.then(Promise.reject) gets a reference to the reject method and passes just that function reference. It no longer has any connection to the Promise object. This means that the this value when the reject() method is called will be incorrect and it does not allow that.
As Patrick mentioned in a comment, it's the same reason you can't do this:
let reject = Promise.reject;
reject("whatever");
Methods need to be called with the context of their object unless they are specifically designed to not need the context of their object (there are some instances of that).
If you want a shortcut, you could do this:
something.then(Promise.reject.bind(Promise))
That will bind the Promise object to the method (by essentially creating a stub function that calls it as Promise.reject()).
Other related answers:
Why does this throw an undefined exception?
When you pass 'this' as an argument
Object methods assigned to variables or function arguments fail when invoked
Assiging a method to a variable in Javascript
Uncaught TypeError: this.method is not a function - Node js class export
I am trying to understand the difference between the 3 options:
.then(myCallback)
.then(myCallback())
.then(() => { myCallback() })
The myCallback function returns nothing and is used only for its side effects, so I don't need it to pass anything back to the promise chain. What I don't understand is why in my code only the second option triggers the function, when it seems like all the 3 should.
UPDATE: Here is the code with the bare essentials
serverCall(url, data) // fetch function
.then((response) => response.json())
.then(myCallback) // not running, only when () added
.catch((error) => { console.log(error) })
const myCallback = () => {
anotherServerCall(...).then(...)
}
UPDATE 2
After some digging I see that having .then((response) => response.json()) as the first then response is what is preventing .then(myCallback) to execute. Still no idea why...
All three should trigger the function, but the order differs between the approaches. If you're sometimes seeing evidence that the serverCall or myCallback aren't being invoked, then that has something to do with the particulars of those functions, not the ways you are calling them.
To demonstrate, consider two proxies for serverCall and myCallback that we know will always work. Let's apply each idea in your question to those:
This is the "normal" way to use then. Pass it a function that is invoked after the promise to which it is attached...
function serverCall() {
console.log('began server call');
return new Promise(function(resolve) {
setTimeout(() => {
console.log('completed server call');
resolve();
}, 2);
});
}
function myCallback() {
console.log('callback called');
}
serverCall().then(myCallback).then(() => console.log('done'));
// produces:
// began server call
// completed server call
// callback called
// done
Your first and third ideas are almost the same. Pass then a function which is invoked after the promise. In your third idea, the function isn't the callback, it's a function that calls the callback. One more stack frame, but the exact same effect...
function serverCall() {
console.log('began server call');
return new Promise(function(resolve) {
setTimeout(() => {
console.log('completed server call');
resolve();
}, 2);
});
}
function myCallback() {
console.log('callback called');
}
serverCall().then(() => { myCallback() }).then(() => console.log('done'))
// produces:
// began server call
// completed server call
// callback called
// done
Your second idea, as a commenter points out, invokes the function and passes it's result to then. The chaining of the then runs synchronously after starting the promise, so the results appear reordered: myCallback runs before the promise completes...
function serverCall() {
console.log('began server call');
return new Promise(function(resolve) {
setTimeout(() => {
console.log('completed server call');
resolve();
}, 2);
});
}
function myCallback() {
console.log('callback called');
}
serverCall().then(myCallback()).then(() => console.log('done'))
// produces:
// began server call
// callback called <------ CHANGED!!!
// completed server call
// done
The only way I've found to duplicate your problem is if the callback returns a function. Options 1 and 3 don't do anything because the returned function isn't being called. Option 2 is called and is successful.
function fetch() {
return new Promise((resolve, reject) => {
resolve();
});
}
function myCallBack() {
return function () {
console.log('Success');
};
}
fetch().then(myCallBack); // nothing
fetch().then(myCallBack()); // Success
fetch().then(() => myCallBack()); // nothing
Your use cases are different because
The first one then call, you are passing a callback to be invoked when then it’s executed, passing a naming function will appear in the stack trace if some error occurred
The second one, execute the callback passed before being passed to the then function and the result of that execution callback will be passing to the then function, so imagine this.
function myCallback(){
return function theRealCallbackPassed(thenResponse){
// do something with then response
}
}
The last one, will define an anonymous arrow function , so what is the diff between
then( () => {} )
And
then( function(){} )
The different is that using arrow function () => {} you have a short syntax and you are binded the function contexto to the current context where the arrow function it’s declared.
While the function() {} syntax is not shorter and it is not auto bindable.
Hope it can help you.
I'm trying to add XPATH evaluation into my form. When user fills XPATH, it's evaluated on a server using AJAX and then return true or false.
The problem is that this function seems to return undefined allways. I suppose it's because of asynchronious behaviour of JS so I used $.when but it didn't helped.
function evalXpath(xpath) {
var test = $.post('/api/test-xpath/', {'xpath': xpath});
test.done(function (data) {
console.log('BEFORE RETURN '+Boolean(data['success']));
return Boolean(data['success']);
})
}
$(document).ready(function () {
$('#id_xpath').on('change', function () {
var xpath = $("#id_xpath").val();
$.when(evalXpath(xpath)).done(function (evaluated) {
console.log('RETURNED '+evaluated);
$('#xpath-valid').text(evaluated ? 'VALID' : 'INVALID');
});
});
});
The console output (as you can see, it's still asynchronious):
Do you have any ideas?
You're really close. A couple of things:
You forgot to return the promise out of evalXpath.
To get proper promise value chaining (e.g., in order for your value from the callback inside evalXpath to then become the resolution value of the promise it returns), use then, not done.
Then when using evalXpath, there's no need for $.when.
So:
function evalXpath(xpath) {
var test = $.post('/api/test-xpath/', {'xpath': xpath});
return test.then(function (data) {
// ^^^^^^ ^^^^
console.log('BEFORE RETURN '+Boolean(data['success']));
return Boolean(data['success']);
})
}
// ...
evalXpath(xpath).then(function (evaluated) {
// ^^^^ (this one could be `done`, but let's be consistent)
I have a block of code that I will be using several times within a then statement in mocha so I turned it into a function. However I also need to call done()within that function and it's out of scope resulting in the error Uncaught ReferenceError: done is not defined. Here's a code snippet:
var collectionChecker = function(results) {
expect(Array.isArray(results), 'Did not return collection');
expect(results.length === numAttr, 'Returned wrong number of models');
done();
};
test('returns a collection with correct number of models', function(done) {
attrs.getAttributeTemplates().then(collectionChecker);
});
How can I pass done() to my function?
I found a workaround by chaining another .then and calling done there but it seems like an ugly way to do it.
You're overthinking it - mocha supports promises, you can return a promise and if it is fulfilled the test will pass (and if the expects throw it will fail):
var collectionChecker = function(results) {
expect(Array.isArray(results), 'Did not return collection');
expect(results.length === numAttr, 'Returned wrong number of models');
};
// just add a return, no `done` here or anywhere
test('returns a collection with correct number of models', function() {
return attrs.getAttributeTemplates().then(collectionChecker);
});