您的代码无法按预期工作的原因是它实际上在做与您认为的有所不同的事情。
假设您有以下内容:
stepOne()
.then(stepTwo, handleErrorOne)
.then(stepThree, handleErrorTwo)
.then(null, handleErrorThree);
为了更好地了解正在发生的事情,让我们假设这是带有try
/ catch
块的同步代码:
try {
try {
try {
var a = stepOne();
} catch(e1) {
a = handleErrorOne(e1);
}
var b = stepTwo(a);
} catch(e2) {
b = handleErrorTwo(e2);
}
var c = stepThree(b);
} catch(e3) {
c = handleErrorThree(e3);
}
的onRejected
处理程序(的第二个参数then
)本质上是一个纠错机制(如catch
块)。如果抛出错误handleErrorOne
,它将被下一个catch块(catch(e2)
)捕获,依此类推。
这显然不是您想要的。
假设无论发生什么问题,我们都希望整个解决方案链失败:
stepOne()
.then(function(a) {
return stepTwo(a).then(null, handleErrorTwo);
}, handleErrorOne)
.then(function(b) {
return stepThree(b).then(null, handleErrorThree);
});
注意:我们可以保留handleErrorOne
它的位置,因为只有在stepOne
拒绝时才会调用它(它是链中的第一个函数,因此我们知道如果链在此刻被拒绝,那只能是由于该函数的诺言而已) 。
重要的变化是其他功能的错误处理程序不属于主要的Promise链。相反,每个步骤都有其自己的“子链”,onRejected
只有在该步骤被拒绝(但主链无法直接到达)时才调用该子链。
这样做的原因是onFulfilled
和onRejected
都是then
方法的可选参数。如果兑现了一个承诺(即已解决),并且then
链中的下一个没有onFulfilled
处理程序,则链将继续进行,直到有一个具有此类处理程序的处理程序为止。
这意味着以下两行是等效的:
stepOne().then(stepTwo, handleErrorOne)
stepOne().then(null, handleErrorOne).then(stepTwo)
但是以下行 并不 等同于以上两行:
stepOne().then(stepTwo).then(null, handleErrorOne)
Angular的promise库$q
基于kriskowal的Q
库(具有更丰富的API,但包含您可以在中找到的所有内容$q
)。GitHub上的Q的api文档可能很有用。Q实现了Promises / A +规范,该规范详细介绍了如何then
以及如何实现承诺解决行为。
编辑:
还要记住,如果您想打破错误处理程序中的链条,它需要返回被拒绝的承诺或引发错误(将被捕获并自动包裹在被拒绝的承诺中)。如果您不返回承诺,then
则将返回值包装在为您解决的承诺中。