Promises:是.done()总是执行,即使.catch()是?

我的承诺问题

我是Promises新手,我一直在阅读Q文档 ,它说:

当你到达一个承诺链的末尾,你应该返回最后的承诺或结束链。

我已经在我的代码中定义了一个Promise Q.Promise方法,使用以下console.log来注销一个执行跟踪:

 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(); }); }); } 

如果每个doSomethingN()正确执行,一切都按预期工作,我得到预期的轨迹:

 1 2 3 done!! 

但是 ,如果任何doSomethingN()失败:

foo()可以正常工作,因为错误函数callback是发生reject(err)时运行的错误函数。

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

我得到以下跟踪(即doSomething1()失败时):

 1 catch!! done!! 

我的问题

我首先想到的是:

好的,我们来处理链接成功失败.done().catch()方法。 如果一切顺利, .done()的callback将被执行,promise将被parsing 。 如果在任何时候出现错误, .catch()的callback将被执行,promise将被拒绝 – 因此, done()将不会被执行。

我认为我错过了.done()工作原理…因为通过查看我的日志logging,我意识到.done()似乎始终在执行 – 是否有错误和.catch()被执行与否 – 这就是我没有想到的。

所以,之后,我删除了.done()的callback,现在foo()

  • 如果在连锁执行过程中出现error ,则可以使用
  • 如果一切正常,则不起作用

我应该重新考虑什么,我怎样才能使它工作?

你应该考虑这样做:

 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'); }); 

如果你想返回一个承诺,在大多数情况下,使用catch没有什么意义(除非你想恢复潜在的错误)。 在返回承诺的方法中使用done是没有意义的。 你宁愿在链条的最后使用这些方法。

请注意, doSomethingX()可以返回一个值或一个承诺,它将工作相同。

catch(cb)只是它的一个别名then(null, cb) ,而且你实际上修正了一个catch错误,所以stream程自然地转向了成功结果。

如果你只是想装饰错误,你应该重新抛出错误,例如正确的passthru可能看起来像:

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

还是你的榜样没有多大意义。 当你回复一个承诺时,你永远不应该使用done 。 如果你想用内部创build的承诺链解决初始化的承诺,你应该把它解决为:

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

没有必要对内部错误进行处理,把这个留给你所承诺的消费者。

和其他点。 如果在创build新的承诺时知道这个承诺将会与其他承诺一起解决,那么没有合理的理由去创造这样的承诺,只要重用一个你打算解决的承诺即可。 这种错误也被认为是推迟反模式

你可以通过解决上次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(); }) } 

考虑使用蓝鸟承诺。 与任何其他承诺库相比,它有许多有用的function。 你可能会觉得很难开始,但一旦你掌握了它,你就会喜欢它。