当Promise.all()拒绝时,停止其他承诺 [英] Stop other promises when Promise.all() rejects
问题描述
虽然关于 Promise.all
的所有问题都集中在如何等待所有承诺,但我想走另一条路 - 当任何承诺失败,停止其他承诺,甚至停止整个脚本。
While all the questions about Promise.all
focus on how to wait for all promises, I want to go the other way -- when any of the promises fails, stop the others, or even stop the whole script.
这是一个简短的例子来说明:
Here's a short example to illustrate:
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'resolve1');
}).then(a => { console.log('then1'); return a; });
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 2000, 'reject2');
}).then(a => { console.log('then2'); return a; });
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'resolve3');
}).then(a => { console.log('then3'); return a; });
Promise.all([promise1, promise2, promise3])
.then(values => { console.log('then', values); })
.catch(err => { console.log('catch', err); throw err; });
// results:
// > "then1"
// > "catch" "reject2"
// > "then3" <------- WHY?
脚本继续解析 promise3
,即使最后的 all(...)。catch()
抛出!有人可以解释原因吗?我可以做些什么来阻止他们拒绝的其他承诺?
The script continues to resolve promise3
, even though the final all(...).catch()
throws! Can someone explain why? What can I do to stop the other promises at the point any of them rejects?
推荐答案
取消承诺不包括在承诺/ A +规范。
然而,一些Promise库有这样的取消延期。以 bluebird 为例:
However, some Promise libraries have such a cancellation extension. Take for example bluebird:
Promise.config({ cancellation: true }); // <-- enables this non-standard feature
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'resolve1');
}).then(a => { console.log('then1'); return a; });
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 2000, 'reject2');
}).then(a => { console.log('then2'); return a; });
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'resolve3');
}).then(a => { console.log('then3'); return a; });
const promises = [promise1, promise2, promise3];
Promise.all(promises)
.then(values => {
console.log('then', values);
})
.catch(err => {
console.log('catch', err);
promises.forEach(p => p.cancel()); // <--- Does not work with standard promises
});
<script src="https://cdn.jsdelivr.net/bluebird/latest/bluebird.core.min.js"></script>
请注意,即使promise3被取消,其 setTimeout
仍然会调用回调。但它不会触发然后
或 catch
回调。就好像这个承诺永远不会达成一个决议......永远。
Note that even though promise3 is cancelled, its setTimeout
callback will still be called. But it will not trigger the then
or catch
callbacks. It will be as if that promise never comes to a resolution ... ever.
如果你想也停止触发计时器事件,那么这与承诺无关,可以使用 clearTimeout
完成。 Bluebird在Promise构造函数中公开了 onCancel
回调函数,它将在取消承诺时调用。因此,您可以使用它来删除计时器事件:
If you want to also stop the timer event from triggering, then this is unrelated to promises, and can be done with clearTimeout
. Bluebird exposes an onCancel
callback function in the Promise constructor, which it will call when a promise is cancelled. So you can use that to remove the timer event:
Promise.config({ cancellation: true }); // <-- enables this non-standard feature
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'resolve1');
}).then(a => { console.log('then1'); return a; });
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 2000, 'reject2');
}).then(a => { console.log('then2'); return a; });
const promise3 = new Promise((resolve, reject, onCancel) => { // Third argument (non-standard)
var timer = setTimeout(resolve, 3000, 'resolve3');
onCancel(_ => {
clearTimeout(timer);
console.log('cancelled 3');
});
}).then(a => { console.log('then3'); return a; });
const promises = [promise1, promise2, promise3];
Promise.all(promises)
.then(values => {
console.log('then', values);
})
.catch(err => {
console.log('catch', err);
promises.forEach(p => p.cancel()); // <--- Does not work with standard promises
});
<script src="https://cdn.jsdelivr.net/bluebird/latest/bluebird.core.min.js"></script>
这篇关于当Promise.all()拒绝时,停止其他承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!