思路
可以使用 Promise.all()和Promise.catch() 结合的方式来实现多个promise的并发执行,并在某个promise失败时尝试重新执行。
首先,将所有的promise放入数组中,并使用Promise.all()来同时执行这些promise,这样可以确保所有的promise都成功执行。
然后,通过catch()方法来捕获拒绝的promise,并在捕获到之后进行重新执行。
代码
const promise1 = () => Promise.resolve(1);
let isFirst = true;
const promise2 = () =>
new Promise((resolve, reject) => {
console.log('promise2 isFirst:', isFirst);
if (isFirst) {
// 模拟promise第一次执行失败,第二次执行成功
reject('2 error');
isFirst = false;
}
resolve('2 success');
});
const promise3 = () => Promise.resolve(3);
const promises = [promise1, promise2, promise3];
Promise.all(
promises.map(promise => {
return promise().catch(error => {
// 如果失败则重新执行该promise
console.error('Promise failed, retrying...:');
return promise();
});
})
)
.then(res => {
console.log('All promises succeeded: ', res);
})
.catch(error => console.error('All promises failed'));
打印结果:
进一步完善
封装一个wrap函数,统一处理失败后重试的这段逻辑,不需要再放在promise.all里面,这样子提高这些promise的可扩展性。
const wrap = (func) => {
// 调用wrap函数,会立即执行func
let last = func();
// 使用闭包,返回一个函数
return () =>
last.catch(() => {
// 失败之后,重新执行func,并保存在last,这样可以保证所有promise只会被执行一次
// 比如某个promise第一次执行失败,重试成功,last将会保存成功后的promise,下次使用到的时候就是返回成功后的这个promise
last = func();
return last.catch(() => {
// will throw error if second failed
throw new Error('second execute failed');
});
});
};
const promise1 = wrap(() => Promise.resolve(1));
let isFirst = true;
const promise2 = wrap(
() =>
new Promise((resolve, reject) => {
console.log('promise2 isFirst:', isFirst);
if (isFirst) {
reject('2 error');
isFirst = false;
}
resolve('2 success');
})
);
const promise3 = wrap(() => Promise.resolve(3));
const promises = [promise1, promise2, promise3];
Promise.all(promises.map(promise => promise()))
.then(res => {
console.log('All promises succeeded: ', res);
})
.catch(error => console.error('All promises failed'));
打印结果:
补充(Promise.allSettled())
官方:Promise.allSettled()
Promise.allSettled来判断多个Promise的执行结果,包括成功和失败。Promise.allSettled返回一个新的Promise对象,该对象在所有给定的Promise已被决议或拒绝后完成,并带有一个对象数组,每个对象表示对应的Promise结果。
例子:
const promises = [promise1, promise2, promise3];
Promise.allSettled(promises)
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Promise ${index + 1} fulfilled with value:`, result.value);
} else {
console.log(`Promise ${index + 1} rejected with reason:`, result.reason);
}
});
});
在上述例子中,promises数组包含多个Promise对象。Promise.allSettled等待所有Promise对象都被决议或拒绝后,返回一个结果数组。结果数组中的每个对象包含了对应Promise的状态和结果。使用forEach循环遍历结果数组,根据状态输出相应的信息。
注意:Promise.allSettled是ES2020中新增的方法,如果需要在较旧的环境中使用该方法,可以使用Promise.all和Promise.catch的组合来实现类似的功能。
该方法是Promise 并发Promise.allSettled()方法之一。当您有多个不依赖于彼此才能成功完成的异步任务,或者您总是想知道每个 Promise 的结果时,通常使用Promise.allSettled()。
相比之下,Promise.all()如果任务相互依赖,或者如果您想在其中任何一个任务拒绝时立即拒绝,则返回的 Promise 可能更合适。