请考虑以下代码,其中包含Bluebird' Promise.settle的简化实现:
kill %1
这将记录" 3个余额中的2个已更新"。为什么这与普通的Promise.all不同?难道不总是实现仍然包含被拒绝的承诺作为其第一个元素吗?
答案似乎在于我对承诺如何运作的困惑。如果我在控制台中创建一个被拒绝的承诺,那么它就是这样:
var a = Promise.reject('a');
var b = Promise.resolve('b');
var c = Promise.resolve('c');
var promises = [a,b,c];
function settled(promises) {
var alwaysFulfilled = promises.map(function (p) {
return p.then(
function onFulfilled(value) {
return { state: 'fulfilled', value: value };
},
function onRejected(reason) {
return { state: 'rejected', reason: reason };
}
);
});
return Promise.all(alwaysFulfilled);
}
//Update status message once all requests finish
settled(promises).then(function (outcomes) {
var count = 0;
outcomes.forEach(function (outcome) {
if (outcome.state == 'fulfilled') count++;
});
console.log(count + ' out of ' + outcomes.length + ' balances were updated');
});
为什么c"已解决"?
答案 0 :(得分:4)
理解您的问题的关键是,当您在.then()
或.catch()
中提供拒绝处理程序时,您告诉承诺系统您已经"处理"拒绝。因此,除非您的拒绝处理程序本身抛出或返回被拒绝的promise本身,否则该拒绝处理程序的返回值将进入已履行的承诺,而不是被拒绝的承诺。下面解释的更多......
事实上,反过来也是如此。如果您有拒绝处理程序并且基于拒绝类型,您希望拒绝继续传播回被拒绝的承诺,您必须从拒绝处理程序抛出错误或返回被拒绝的承诺。
这将记录" 3个余额中的2个已更新"。为什么这样做 不同于简单的Promise.all?
Promise.all()
一旦获得承诺列表中的第一次拒绝,就会返回被拒绝的承诺。它不一定返回所有结果,如果您传递的任何承诺被拒绝,它将被拒绝。一旦一个承诺被拒绝,它就基本上放弃了。这是Promise.settle()
的重点。它将为您提供所有结果,即使有些被拒绝,您也可以剔除所有结果。
不应该总是实现仍然包含被拒绝的承诺 第一个元素?
如下所述,当你在.then()
中有拒绝处理程序并且拒绝处理程序没有throw
或者返回被拒绝的承诺时(例如它返回正常值,就像你正在做的那样),那么承诺拒绝被视为已处理,并且.then()
处理程序产生的承诺得以履行,而不是被拒绝。以下步骤中的更多解释......
答案似乎在于我对承诺如何运作的困惑。如果我 在控制台中创建一个被拒绝的承诺,然后就这样...... 为什么c"已解决"?
首先,.then()
会返回新的承诺。因此a.then()
未返回a
。它返回了一个新的承诺,它是.then()
处理程序中发生的事情的产物。
执行此操作时:
var c = Promise.reject('a').then(undefined, function() {});
以下是发生的事情:
'a'
创建被拒绝的承诺。.then()
链接到它,从而创建新的承诺并将其返回到变量c
。.then()
的第二个处理程序。在调试或设计代码时,请记住这总是异步调用(这有时会使调试器中的人感到困惑)。undefined
。在这一点上,Promise系统考虑拒绝和处理" .then()
的结果是一个履行的承诺,其值为undefined
(这是您的处理程序返回的内容)。如果您希望结果仍然被拒绝,那么您可以throw
或者您可以从拒绝处理程序返回被拒绝的承诺。它以这种方式完成,因此您可以处理"拒绝并保持承诺链成功。此外,未处理的拒绝将导致拒绝的承诺,但是使用拒绝处理程序会告知承诺系统您的代码正在处理拒绝,并且将根据拒绝处理程序的返回结果形成最终的承诺。
因此,所有这些都会导致c
被拒绝:
// no reject handler
var c = a.then(function() {});
// throw from reject handler
var c = a.then(undefined, function() { throw new Error("whatever")});
// return rejected promise from reject handler
var c = a.then(undefined, function() { return Promise.reject("whatever")});
但是,如果你有一个拒绝处理程序并且它既没有throw
也没有返回被拒绝的承诺,那么就会考虑拒绝"处理"并且使用处理程序返回的任何值来解决生成的promise。