承诺:是否总是执行 .done(),即使 .catch() 是?

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

我的 Promise 问题

我是 Promises 的新手,我一直在阅读 Q Documentation,其中写道:

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

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

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() 工作正常,因为错误函数回调是在 reject(err) 发生时运行的函数:

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

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

1
catch!!
done!!

我的问题

我最初的想法是:

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.

我想我遗漏了一些关于 .done() 是如何工作的...因为通过查看我的日志记录跟踪,我意识到 .done() 似乎总是在执行 - 无论是否有错误和 .catch() 是否执行 - 这是我没有预料到的。

所以,在那之后,我删除了 .done() 的回调,现在 foo():

我应该重新考虑什么以及could/should我如何让它发挥作用?

您可以通过在上一个 then 回调中解析 promise 使其工作。

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

考虑使用 bluebird 作为承诺。与任何其他 promise 库相比,它具有许多有用的功能。你可能会发现开始它很困难,但一旦你掌握了它,你就会爱上它。

您应该考虑这样做:

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

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

请注意,doSomethingX() 可以 return 一个值或一个承诺,它们的作用是一样的。

catch(cb)只是then(null, cb)的别名,而你实际上修复了catch中的一个错误,所以流自然转向成功 结果 done.

如果你只想修饰 catch 中的错误,你应该在之后重新抛出错误,例如正确的直通可能看起来像:

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

你的例子仍然没有多大意义。当你 return 一个承诺时,你不应该使用 done。如果你想用内部创建的承诺链来解析初始化的承诺,你应该将它解析为:

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

不需要内部错误处理,将其留给您return承诺的消费者。

还有一点。如果在创建新承诺时您知道它将与其他承诺一起解决,那么就没有逻辑理由创建这样的承诺,只需重用您计划解决的承诺即可。这种错误也被创造为 deferred anti-pattern