promise.all 和 promise.allSettled 的区别
Promise.all 与 Promise.allSettled 的区别详解
这两个方法都是用于处理多个Promise的并发执行,但在行为和结果处理上有重要区别。
📊 核心区别对比表
| 特性 | Promise.all | Promise.allSettled |
|---|---|---|
| 失败处理 | 一个失败立即拒绝整个Promise | 等待所有Promise完成,无论成功失败 |
| 返回值 | 成功值的数组 | 对象数组,包含状态和值/原因 |
| 适用场景 | 需要所有操作都成功的场景 | 需要知道每个操作最终结果的场景 |
| 错误处理 | 只能捕获第一个错误 | 可以获取每个Promise的详细结果 |
🔍 详细解析
Promise.all - "全有或全无"
// 基本语法
Promise.all([promise1, promise2, promise3, ...])
.then(values => {
// 所有Promise都成功时执行
})
.catch(error => {
// 任何一个Promise失败时立即执行
});
特点:
- 如果所有Promise都成功,返回成功值的数组
- 如果任何一个Promise失败,立即拒绝,并返回第一个错误
- 适用于相互依赖的操作
示例:
const p1 = Promise.resolve('成功1');
const p2 = Promise.resolve('成功2');
const p3 = Promise.reject('失败!');
const p4 = Promise.resolve('成功4');
// 所有成功的情况
Promise.all([p1, p2, p4])
.then(results => {
console.log(results); // ['成功1', '成功2', '成功4']
})
.catch(error => {
console.log('这里不会执行');
});
// 有失败的情况
Promise.all([p1, p2, p3, p4])
.then(results => {
console.log('这里不会执行');
})
.catch(error => {
console.log(error); // '失败!' - 立即捕获第一个错误
// p4的结果被忽略,即使它成功了
});
Promise.allSettled - "全部见分晓"
// 基本语法
Promise.allSettled([promise1, promise2, promise3, ...])
.then(results => {
// 所有Promise都完成时执行(无论成功失败)
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('成功:', result.value);
} else {
console.log('失败:', result.reason);
}
});
});
特点:
- 等待所有Promise完成(成功或失败)
- 返回对象数组,每个对象包含状态和值/原因
- 永远不会被拒绝
- 适用于需要知道每个操作结果的场景
示例:
const p1 = Promise.resolve('成功1');
const p2 = Promise.resolve('成功2');
const p3 = Promise.reject('失败3');
const p4 = Promise.reject('失败4');
Promise.allSettled([p1, p2, p3, p4])
.then(results => {
console.log(results);
// 输出:
// [
// { status: 'fulfilled', value: '成功1' },
// { status: 'fulfilled', value: '成功2' },
// { status: 'rejected', reason: '失败3' },
// { status: 'rejected', reason: '失败4' }
// ]
// 处理结果
const successful = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
const failed = results
.filter(r => r.status === 'rejected')
.map(r => r.reason);
console.log('成功的:', successful); // ['成功1', '成功2']
console.log('失败的:', failed); // ['失败3', '失败4']
});
🎯 实际应用场景
场景1:多个API请求(使用Promise.all)
// 需要所有用户数据都加载成功才能显示页面
async function loadUserDashboard(userId) {
try {
const [userInfo, userOrders, userPreferences] = await Promise.all([
fetch(`/api/users/${userId}`).then(r => r.json()),
fetch(`/api/users/${userId}/orders`).then(r => r.json()),
fetch(`/api/users/${userId}/preferences`).then(r => r.json())
]);
// 所有数据都成功获取,渲染仪表板
renderDashboard(userInfo, userOrders, userPreferences);
} catch (error) {
// 任何一个API失败就显示错误页面
showErrorPage('加载用户数据失败');
}
}
场景2:批量图片上传(使用Promise.allSettled)
// 图片上传,希望知道每个文件的上传结果
async function uploadMultipleImages(files) {
const uploadPromises = files.map(file =>
uploadImage(file).catch(error => {
// 捕获单个上传错误,但继续其他上传
return { error: error.message, fileName: file.name };
})
);
const results = await Promise.allSettled(uploadPromises);
const summary = {
successful: [],
failed: []
};
results.forEach(result => {
if (result.status === 'fulfilled') {
if (result.value.error) {
summary.failed.push({
fileName: result.value.fileName,
error: result.value.error
});
} else {
summary.successful.push(result.value);
}
} else {
summary.failed.push({
error: result.reason.message
});
}
});
console.log(`上传完成: ${summary.successful.length} 成功, ${summary.failed.length} 失败`);
return summary;
}
场景3:表单多个验证(混合使用)
async function validateForm(formData) {
// 这些验证可以并行执行,但需要全部通过
const validationPromises = [
validateEmail(formData.email),
validatePassword(formData.password),
validateUsername(formData.username)
];
try {
const results = await Promise.all(validationPromises);
return { isValid: true, errors: [] };
} catch (error) {
// 但我们需要知道所有验证错误,而不仅仅是第一个
// 所以更好的做法是使用 allSettled
const results = await Promise.allSettled(validationPromises);
const errors = results
.filter(result => result.status === 'rejected')
.map(result => result.reason);
return { isValid: false, errors };
}
}
🔧 实用工具函数
1. 带超时的Promise.all
function promiseAllWithTimeout(promises, timeoutMs) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('操作超时')), timeoutMs);
});
return Promise.all([...promises, timeoutPromise]);
}
2. 分类处理结果
function categorizeResults(results) {
return {
fulfilled: results.filter(r => r.status === 'fulfilled').map(r => r.value),
rejected: results.filter(r => r.status === 'rejected').map(r => r.reason),
all: results
};
}
// 使用
Promise.allSettled(promises)
.then(categorizeResults)
.then(({ fulfilled, rejected }) => {
console.log(`成功: ${fulfilled.length}, 失败: ${rejected.length}`);
});
3. 逐步降级策略
async function fallbackStrategy(primaryAction, fallbackActions) {
try {
return await primaryAction();
} catch (error) {
// 主操作失败,尝试所有备用方案
const results = await Promise.allSettled(fallbackActions.map(action => action()));
const firstSuccess = results.find(result => result.status === 'fulfilled');
if (firstSuccess) {
return firstSuccess.value;
}
// 所有备用方案都失败
throw new Error('所有操作都失败了');
}
}
💡 选择指南
使用 Promise.all 当:
- 所有操作都必须成功才能继续
- 操作之间有依赖关系
- 需要原子性操作(要么全成功,要么全失败)
使用 Promise.allSettled 当:
- 需要知道每个操作的最终状态
- 操作之间相互独立
- 希望部分失败不影响其他操作的结果收集
- 进行批量操作,需要生成汇总报告
记住这个简单的规则:"要么都要,要么都不要"用all,"我全都要知道"用allSettled。

浙公网安备 33010602011771号