I am new to Promises
and I've been reading the Q Documentation, where it says:
When you get to the end of a chain of promises, you should either return the last promise or end the chain.
I have defined a Promise in my code the Q.Promise
way, with the following console.log
s to log out an execution trace:
function foo(){
return Q.Promise(function(resolve, reject) {
doSomething()
.then(function() {
console.log('1');
return doSomething1();
})
.then(function() {
console.log('2');
return doSomething2();
})
.then(function() {
console.log('3');
return doSomething3();
})
.catch(function(err) {
console.log('catch!!');
reject(err);
})
.done(function() {
console.log('done!!');
resolve();
});
});
}
In case every doSomethingN()
executes correctly, everything works as intended and I get the expected trace:
1
2
3
done!!
But in case any of the doSomethingN()
fails:
foo()
works correctly, because the error function callback is the one that runs whenever a reject(err)
occurs:
foo().then(function() { /* */ }, function(err) { /* this runs! */ });
And I get the following trace (ie. when doSomething1()
fails):
1
catch!!
done!!
What I thought at first was the following:
Okay, let's handle the chaining success and failure in both:
.done()
and.catch()
methods. If everything goes well.done()
's callback will be executed and the promise will be resolved. In case there's an error at any point,.catch()
's callback will be executed and the promise will be rejected - and because of that,done()
won't be executed.
I think I am missing something about how the .done()
works... because by having a look at my logging trace, I realized that .done()
seems to be executing always - whether there is an error and .catch()
is executed or not - and that is what I wasn't expecting.
So, after that, I removed .done()
's callback and now foo()
:
error
during the chain executionWhat should I reconsider and how could/should I make it work?
The Promise constructor takes a function (an executor) that will be executed immediately and passes in two functions: resolve , which must be called when the Promise is resolved (passing a result), and reject , when it is rejected (passing an error).
catch " around the executor automatically catches the error and turns it into rejected promise. This happens not only in the executor function, but in its handlers as well. If we throw inside a . then handler, that means a rejected promise, so the control jumps to the nearest error handler.
The finally() method of a Promise schedules a function, the callback function, to be called when the promise is settled. Like then() and catch() , it immediately returns an equivalent Promise object, allowing you to chain calls to another promise method, an operation called composition.
catch(cb)
is just an alias for then(null, cb)
, and you've actually fixed an error in catch
, so flow naturally turned to success result in done
.
If you want to just decorate the error in catch, you should rethrow the error afterwards, e.g. proper passthru may look as:
catch(function (err) {
console.log(err);
throw err;
});
Still your example doesn't make much sense. You should never use done
, when you return a promise. If you want to resolve initialized promise with internally created chain of promises, you should just resolve it as:
resolve(doSomething()
.then(function() {
console.log('1');
return doSomething1();
})
....
.then(function() {
console.log('N');
return doSomethingN();
}));
There's no need for internal error handling, leave that to consumer of promise which you return.
And other point. If when creating new promise you know it will be resolved with other one, then there's no logical reason to create such promise, just reuse one you planned to resolve with. Such error was also coined as deferred anti-pattern
You should consider doing this:
function foo() {
// Calling .then() on a promise still return a promise.
// You don't need Q.Promise here
return doSomething()
.then(function(doSomethingResult) {
console.log('1');
return doSomething1();
})
.then(function(doSomething1Result) {
console.log('2');
return doSomething2();
})
.then(function(doSomething2Result) {
console.log('3');
return doSomething3();
});
}
foo()
.then(function(fooResult) {
console.log(fooResult); // fooResult should be what is returned by doSomething3()
})
.catch(function(err) {
console.error(err); // Can be thrown by any
})
.done(function() {
console.log('I am always executed! error or success');
});
If you want to return a promise, in most cases it does not make much sense to use catch (unless you want to recover potential errors). It never make sense to use done
in a method returning a promise. You would rather use these methods at the very end of the chain.
Notice that doSomethingX()
can return either a value, or a promise, it will work the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With