Javascript 承诺:即使.catch()是,也总是执行.done()吗? 我的承诺问题

Javascript 承诺:即使.catch()是,也总是执行.done()吗? 我的承诺问题,javascript,node.js,promise,q,Javascript,Node.js,Promise,Q,我不熟悉《承诺》,我一直在阅读《承诺》,其中写道: 当你到达承诺链的末端时,你应该要么返回最后一个承诺,要么结束承诺链 我在我的代码中以Q.Promise的方式定义了一个承诺,使用以下console.logs注销执行跟踪: function foo(){ return Q.Promise(function(resolve, reject) { doSomething() .then(function() { console.log('1'); re

我不熟悉《承诺》,我一直在阅读《承诺》,其中写道:

当你到达承诺链的末端时,你应该要么返回最后一个承诺,要么结束承诺链

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

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()
失败:

1
catch!!
done!!
foo()
工作正常,因为每当发生
拒绝(err)
时,都会运行错误函数回调:

foo()

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

我的问题 我最初的想法是:

好的,让我们同时处理
.done()
.catch()
方法中的链接successfailure。如果一切顺利,
.done()
的回调将被执行,承诺将得到解决。如果在任何时候出现错误,
.catch()
的回调将被执行,承诺将被拒绝,因此,
done()
将不会执行

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

因此,在那之后,我删除了
.done()
的回调,现在是
foo()

  • 如果在链执行过程中出现
    错误
    ,则此功能有效
  • 如果一切正常,则不起作用

我应该重新考虑什么?我应该如何使它工作?

您可以通过在最后一次回拨中解决承诺来使它工作

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

考虑使用“承诺”。与任何其他promise库相比,它有许多有用的特性。你可能发现很难开始,但是一旦你抓住它,你就会爱上它。

< P>你应该考虑这样做:

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
中的一个错误,因此流自然会变成
done
中的成功结果

如果您只想修饰catch中的错误,则应在之后重新显示该错误,例如,正确的passthru可能如下所示:

catch(function (err) {
   console.log(err);
   throw err;
});
你的例子仍然没有多大意义。当您返回承诺时,绝不应使用
done
。如果您希望使用内部创建的承诺链解析初始化的承诺,则应将其解析为:

resolve(doSomething()
  .then(function() {
    console.log('1');
    return doSomething1();
  })
  ....
  .then(function() {
    console.log('N');
    return doSomethingN();
  }));
不需要进行内部错误处理,将其交给承诺的消费者处理


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

首先,避免错误!您的问题不在于
done
,而在于
catch
。捕获错误意味着您已经处理了错误,并且从
.catch(…)
返回的承诺(您附加到
.done()
的承诺)将得到履行@Bergi恐怕我不明白你在第二次评论中想解释什么。。。这个
.catch()
有什么问题?它返回一个最终会实现的承诺,这就是为什么即使出现错误,
done
也会运行的原因。看看@Bergi,你给出的关于这个主题的链接非常有用!当所有doSomethingN呼叫都解决后,它仍然不起作用吗?我同意@Bergi的观点。@KunalKapadia:不,它按照你的意图“起作用”,但你的回答仍然显示出不好的做法@KunalKapadia,我正在寻找正确的解决方案。我以前已经考虑过你的解决方案,但因为Bergi的话,我放弃了它。@Bergi同意你的看法。从我的代码中删除了反模式。指出得很好,解释得很清楚,@SebastienLorber!我还有最后一个问题,关于在哪里使用
延迟
新承诺
:因此,我应该只使用这些(一个或另一个)在函数中进行“设置”,我希望返回承诺。在这种情况下,在
foo()
中,您不需要
延迟
新承诺
,因为这已经在每个
doSomethingN()
(已经返回承诺)中完成,您可以通过
直接获得这些承诺。。。我说得对吗?我想我明白这是怎么回事了。。。!和@SebastienLorber,如果任何
doSomethingN()
函数抛出了
拒绝
。。。如果你的
dosothingx()
操作不需要使用之前要执行的结果,你可以并行启动它们(使用
Q.all([smth1Promise,smth2Promise,smth3Promise])。spread(res1,res2,res3)
…非常好。我唯一的问题是:用
resolve()
包装链有什么区别?区别与
resolve(promise)
promise.done(resolve,reject)
相同。两者都会做完全相同的事情,仍然是f