Promise.settle 和承诺履行与拒绝
Promise.settle and promise fulfillment vs rejection
考虑以下代码,其中包含 Bluebird 的 Promise.settle 的简化实现:
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');
});
这将记录“更新了 3 个余额中的 2 个”。为什么这与普通的 Promise.all 不同? alwaysFulfilled 不应该仍然包含一个被拒绝的承诺作为它的第一个元素吗?
答案似乎在于我对 promise 的运作方式感到困惑。如果我在控制台中创建了一个被拒绝的承诺,那么它就像这样:
var a = Promise.reject('a');
var b = a.then(function() {}, undefined);
var c = a.then(undefined, function() {});
a
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: "a"}
b
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: "a"}
c
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}
为什么是c"resolved"?
理解您的问题的关键是,当您在 .then()
或 .catch()
中提供拒绝处理程序时,您是在告诉承诺系统您是 [=66= 】 拒绝。因此,除非您的拒绝处理程序本身抛出或 returns 拒绝承诺本身,否则该拒绝处理程序的 return 值将进入已履行的承诺,而不是拒绝的承诺。下面将对此进行更多解释...
其实反之亦然。如果你有一个拒绝处理程序并且基于拒绝的类型,你希望拒绝继续传播回被拒绝的承诺,你必须从拒绝处理程序中抛出错误或 return 一个被拒绝的承诺。
This will log "2 out of 3 balances were updated". Why does this work
differently than a plain Promise.all?
Promise.all()
return一旦在给定的承诺列表中获得第一个拒绝,它就会被拒绝。它不一定 return 所有结果,如果你通过它的任何承诺被拒绝,它 return 就会被拒绝。一旦一个承诺被拒绝,它基本上就放弃了。这就是 Promise.settle()
的意义所在。它会为您提供所有结果,即使有些结果被拒绝,您也可以筛选所有结果。
Shouldn't alwaysFulfilled still contain a rejected promise as its
first element?
如下所述,当您在 .then()
中有一个拒绝处理程序并且该拒绝处理程序没有 throw
或 return 被拒绝的承诺(例如它 return s 是一个正常值,就像您正在做的那样),那么该承诺拒绝被视为已处理,并且来自 .then()
处理程序的结果承诺得到履行,而不是被拒绝。下面的步骤中有更多解释...
The answer seems to lie in my confusion over how promises work. If I
create a rejected promise in the console and .then it like so...
Why is c "resolved"?
首先,.then()
return 是一个新的承诺。所以 a.then()
不是 returning a
。这是 return 一个新的承诺,它是 .then()
处理程序中发生的事情的产物。
当你这样做时:
var c = Promise.reject('a').then(undefined, function() {});
这是正在发生的事情:
- 您创建了一个被拒绝的承诺,原因是
'a'
。
- 您将
.then()
链接到它,这会创建一个新的承诺,并且 return 将其放入您的变量 c
。
- 然后,因为最初的承诺被拒绝,所以调用
.then()
的第二个处理程序。在调试或设计代码时,请记住这始终是异步调用的(这有时会使调试器中的人感到困惑)。
- 你 return
undefined
来自拒绝处理程序。此时,Promise 系统认为拒绝 "handled" 并且 .then()
的结果是具有 undefined
值的已履行承诺(这就是您的处理程序 returned)。
如果您希望结果仍然被拒绝,那么您可以 throw
或者您可以 return 来自拒绝处理程序的拒绝承诺。以这种方式完成,因此您可以 "handle" 拒绝并保持承诺链成功运行。此外,未处理的拒绝将导致拒绝的承诺,但是拒绝处理程序会告诉承诺系统您的代码正在处理拒绝,并且将根据拒绝处理程序的 return 结果形成最终的承诺.
所以,所有这些都会导致 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
也没有 return 被拒绝的承诺,那么拒绝被视为 "handled" 并且最终的承诺被解决无论你的处理程序有什么价值 returns.
考虑以下代码,其中包含 Bluebird 的 Promise.settle 的简化实现:
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');
});
这将记录“更新了 3 个余额中的 2 个”。为什么这与普通的 Promise.all 不同? alwaysFulfilled 不应该仍然包含一个被拒绝的承诺作为它的第一个元素吗?
答案似乎在于我对 promise 的运作方式感到困惑。如果我在控制台中创建了一个被拒绝的承诺,那么它就像这样:
var a = Promise.reject('a');
var b = a.then(function() {}, undefined);
var c = a.then(undefined, function() {});
a
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: "a"}
b
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: "a"}
c
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}
为什么是c"resolved"?
理解您的问题的关键是,当您在 .then()
或 .catch()
中提供拒绝处理程序时,您是在告诉承诺系统您是 [=66= 】 拒绝。因此,除非您的拒绝处理程序本身抛出或 returns 拒绝承诺本身,否则该拒绝处理程序的 return 值将进入已履行的承诺,而不是拒绝的承诺。下面将对此进行更多解释...
其实反之亦然。如果你有一个拒绝处理程序并且基于拒绝的类型,你希望拒绝继续传播回被拒绝的承诺,你必须从拒绝处理程序中抛出错误或 return 一个被拒绝的承诺。
This will log "2 out of 3 balances were updated". Why does this work differently than a plain Promise.all?
Promise.all()
return一旦在给定的承诺列表中获得第一个拒绝,它就会被拒绝。它不一定 return 所有结果,如果你通过它的任何承诺被拒绝,它 return 就会被拒绝。一旦一个承诺被拒绝,它基本上就放弃了。这就是 Promise.settle()
的意义所在。它会为您提供所有结果,即使有些结果被拒绝,您也可以筛选所有结果。
Shouldn't alwaysFulfilled still contain a rejected promise as its first element?
如下所述,当您在 .then()
中有一个拒绝处理程序并且该拒绝处理程序没有 throw
或 return 被拒绝的承诺(例如它 return s 是一个正常值,就像您正在做的那样),那么该承诺拒绝被视为已处理,并且来自 .then()
处理程序的结果承诺得到履行,而不是被拒绝。下面的步骤中有更多解释...
The answer seems to lie in my confusion over how promises work. If I create a rejected promise in the console and .then it like so... Why is c "resolved"?
首先,.then()
return 是一个新的承诺。所以 a.then()
不是 returning a
。这是 return 一个新的承诺,它是 .then()
处理程序中发生的事情的产物。
当你这样做时:
var c = Promise.reject('a').then(undefined, function() {});
这是正在发生的事情:
- 您创建了一个被拒绝的承诺,原因是
'a'
。 - 您将
.then()
链接到它,这会创建一个新的承诺,并且 return 将其放入您的变量c
。 - 然后,因为最初的承诺被拒绝,所以调用
.then()
的第二个处理程序。在调试或设计代码时,请记住这始终是异步调用的(这有时会使调试器中的人感到困惑)。 - 你 return
undefined
来自拒绝处理程序。此时,Promise 系统认为拒绝 "handled" 并且.then()
的结果是具有undefined
值的已履行承诺(这就是您的处理程序 returned)。
如果您希望结果仍然被拒绝,那么您可以 throw
或者您可以 return 来自拒绝处理程序的拒绝承诺。以这种方式完成,因此您可以 "handle" 拒绝并保持承诺链成功运行。此外,未处理的拒绝将导致拒绝的承诺,但是拒绝处理程序会告诉承诺系统您的代码正在处理拒绝,并且将根据拒绝处理程序的 return 结果形成最终的承诺.
所以,所有这些都会导致 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
也没有 return 被拒绝的承诺,那么拒绝被视为 "handled" 并且最终的承诺被解决无论你的处理程序有什么价值 returns.