如果任何Promise被拒绝,如何计算Promise.all中成功的次数?



我目前正试图弄清楚是否有可能做这样的事情:

async function(x) {
...
}
try {
await Promise.all([function(1), function(2), function(3), ...]);
} catch (err) {
// Count number of successful Promises resolved at the point when one is rejected
return statistics(num_success);
}

这可能吗?我试图在catch块中这样做的原因是,如果有任何错误,我可以立即终止函数。

如果可能的话,我该怎么做呢?

如果你想让所有的承诺都运行,直到它们被解决(完成或拒绝),你可以使用Promise。拉斐尔·皮克罗的评论和亨利的回答都解决了。

然而,为了保存诺言。所有对拒绝立即做出反应的行为,你需要一些额外的自定义行为。这听起来是个包装promise .all的好理由。

/**
* Receives an array, like Promise.all, and runs until the first rejection.
*
* Unlike Promise.all, but like Promise.allSettled, this will always resolve
* to an object; however, like Promise.all, this will resolve as soon as it
* encounters the first rejection.
*
* Returns a promise that resolves to an object with these properties:
*   success: boolean, whether Promise.all would have succeeded
*   count: number, number of resolved Promises at the time of return
*   results: Array, result array containing all resolved Promises/values
*   error: any, the reject value that caused this to fail, or null
*/
function allWithProgress(arrayOfPromises) {
const results = new Array(arrayOfPromises);
let count = 0;

/**
* Given an input to Promise.resolve, increments results+count 
* when complete.
*/
function wrap(valueOrThenable, index) {
return Promise.resolve(valueOrThenable).then(x => {
results[index] = x;
count++;
return x;
});
}

// slice(0) prevents the results array from being modified.
// You could also add a condition check that prevents `wrap` from
// modifying the results after it returns.
return Promise
.all(arrayOfPromises.map(wrap)) // or "(e, i) => wrap(e, i)"
.then(x => ({success: true, count, results: results.slice(0), error: null}))
.catch(e => ({success: false, count, results: results.slice(0), error: e}));
}
// Test harness below
function timeoutPromise(string, timeoutMs) {
console.log("Promise created: " + string + " - " + timeoutMs + "ms");
return new Promise(function(resolve, reject) {
window.setTimeout(function() {
console.log("Promise resolved: " + string + " - " + timeoutMs + "ms");
resolve(string);
}, timeoutMs);
});
}
Promise.resolve().then(() => {
// success
return allWithProgress([
timeoutPromise("s1", 1000),
timeoutPromise("s2", 2000),
timeoutPromise("s3", 3000),
"not a promise"
]).then(console.log);
}).then(() => {
// failure
return allWithProgress([
timeoutPromise("f1", 1000),
timeoutPromise("f2", 2000)
// rejects with a String for Stack Snippets; use an Error in real code 
.then(() => Promise.reject("f2 failed")),
timeoutPromise("f3", 3000),
"not a promise"
]).then(console.log);
});

请注意,ES6承诺不能以任何标准方式取消或回滚,所以在测试用例中,f3没有被阻止完成。如果在运行中停止这些承诺很重要,则需要自己编写该逻辑。

正如Raphael PICCOLO所说,您可以使用Promise.allSettled<T = any>(...promises: Promise<T>[])。它返回一个包含具有status属性的对象的数组的promise,赋值为"completed";或"被拒绝",根据每一个承诺实现疾病或拒绝。如果承诺已经实现,value属性将可用,如果它拒绝,reason属性将可用。

示例代码:

//...
const promises = []; //Array with promises.
let count = 0;
Promise.allSettled(promises)
.then(settled => {
settled.forEach(({ status, value, reason }) => {
if (status === 'fulfilled')
count++;
})
})
.then(() => statistics(count));
//...

最新更新