Promises: .done () is always executed, even if .catch () is there?

My promise question

I am new to Promises and I read Q Documentation that says:

When you get to the end of the promises chain, you must either return the last promise or end the chain.

I defined Promise in my Q.Promise code, with the following console.log , to exit the 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(); }); }); } 

If each doSomethingN() runs correctly, everything works as intended, and I get the expected trace:

 1 2 3 done!! 

But if any of doSomethingN() :

foo() works correctly since the error function callback is the one that fires whenever the reject(err) event occurs:

foo().then(function() { /* */ }, function(err) { /* this runs! */ });

And I get the following trace (i.e. when doSomething1() does not work):

 1 catch!! done!! 

My question

At first, I thought the following:

Ok, let the chain handle success and failure in both methods: .done() and .catch() . If all goes well .done() will call back and the promise will be resolved. In the event of an error, a callback to .catch() will be executed at any point, and the promise will be rejected - and because of this, done() will not be executed.

I think I'm missing something about how .done() works ... because, looking at my logging trace, I realized that .done() seems to always execute - is there an error and .catch() is executed or not - and I did not expect this.

So after that I removed the .done() and now foo() :

  • works if there is error at run time
  • not working if everything is working correctly

What should I review and how do I / make it work?

+6
source share
3 answers

You should think about 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 makes no sense to use catch (unless you want to recover potential errors). It never makes sense to use done in a method that returns a promise. You prefer to use these methods at the very end of the chain.

Note that doSomethingX() can return either a value or a promise, it will work the same.

+2
source

catch(cb) is just an alias for then(null, cb) , and you really fixed the error in catch , so the thread naturally turned into a done result of success.

If you want to simply decorate the error in catch, you must reset the error again later, for example. The correct passthru might look like this:

 catch(function (err) { console.log(err); throw err; }); 

However, your example does not make much sense. You should never use done when you return a promise. If you want to allow an initialized promise with an inner chain of promises, you should simply allow it as:

 resolve(doSomething() .then(function() { console.log('1'); return doSomething1(); }) .... .then(function() { console.log('N'); return doSomethingN(); })); 

There is no need to handle internal errors, leave this to the consumer of the promise that you will return.

And another point. If, when creating a new promise, you know that it will be resolved with another, then there is no logical reason for creating such a promise, just reuse the one you planned to allow. Such an error was also invented as a delayed anti-pattern.

+5
source

You can make it work by resolving the promise in your last callback.

 function foo(){ return doSomething() .then(function() { console.log('1'); return doSomething1(); }) .then(function() { console.log('2'); return doSomething2(); }) .then(function() { console.log('3'); return doSomething3(); }) } 

Consider bluebird for promises. It has many useful features compared to any other promise library. It may be difficult for you to start it, but as soon as you master it, you will like it.

0
source

All Articles