JavaScript 教程:深入理解 Promise API
Promise 是 JavaScript 异步编程的核心概念之一,它提供了比传统回调函数更优雅的异步处理方式。本文将全面解析 Promise 类提供的 6 个静态方法,帮助你掌握 Promise 的高级用法。
为什么需要 Promise API
在复杂的异步编程场景中,我们经常需要处理多个异步操作的组合、竞争或依赖关系。Promise API 提供了一系列静态方法来简化这些常见模式的处理。
1. Promise.all:并行执行多个 Promise
Promise.all 是最常用的方法之一,它允许我们并行执行多个 Promise,并等待所有 Promise 都完成。
基本用法
let promise = Promise.all([promise1, promise2, ...]);
特点:
- 接收一个可迭代对象(通常是数组)
- 返回一个新的 Promise
- 当所有 Promise 都成功时,返回结果数组
- 顺序与输入顺序一致,不受完成时间影响
- 任何一个 Promise 失败,立即拒绝
实际应用示例
// 同时获取多个用户信息
let userIds = [1, 2, 3];
let userPromises = userIds.map(id => fetch(`/users/${id}`));
Promise.all(userPromises)
.then(responses => Promise.all(responses.map(r => r.json())))
.then(users => {
// 处理所有用户数据
})
.catch(error => {
// 处理任一请求失败的情况
});
注意事项
- 一旦某个 Promise 失败,其他 Promise 的结果会被忽略
- 可以传递非 Promise 值,它们会被直接包含在结果数组中
- 适用于"全部成功或全部失败"的场景
2. Promise.allSettled:获取所有 Promise 的最终状态
Promise.allSettled 是较新的 API,它会等待所有 Promise 完成(无论成功或失败)。
与 Promise.all 的区别
- 不会因为某个 Promise 失败而立即拒绝
- 总是返回一个包含所有 Promise 结果的对象数组
- 每个结果对象包含 status 属性("fulfilled"或"rejected")
使用场景
// 获取多个资源,即使部分失败也要继续处理
Promise.allSettled([
fetch('/data'),
fetch('/config'),
fetch('/user')
]).then(results => {
results.forEach(result => {
if(result.status === 'fulfilled') {
console.log('成功:', result.value);
} else {
console.log('失败:', result.reason);
}
});
});
兼容性处理
对于不支持的环境,可以使用 polyfill:
if(!Promise.allSettled) {
Promise.allSettled = function(promises) {
return Promise.all(promises.map(p =>
Promise.resolve(p).then(
value => ({ status: 'fulfilled', value }),
error => ({ status: 'rejected', reason: error })
)
);
};
}
3. Promise.race:竞速模式
Promise.race 返回第一个完成的 Promise(无论成功或失败)。
典型用法
// 设置超时机制
function fetchWithTimeout(url, timeout) {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('请求超时')), timeout)
)
]);
}
注意事项
- 只关心第一个完成的 Promise
- 其他 Promise 的结果会被忽略
- 适用于超时处理或竞速场景
4. Promise.any:首个成功的 Promise
Promise.any 是较新的 API,它等待第一个成功的 Promise。
特点
- 忽略所有失败的 Promise,直到第一个成功的出现
- 如果所有 Promise 都失败,返回 AggregateError
- 适用于"任一成功即可"的场景
示例
// 尝试多个镜像服务器
Promise.any([
fetch('https://mirror1.com/data'),
fetch('https://mirror2.com/data'),
fetch('https://mirror3.com/data')
]).then(data => {
// 使用第一个成功的响应
}).catch(error => {
// 所有请求都失败了
console.log(error.errors); // 查看所有错误
});
5. Promise.resolve 和 Promise.reject
这两个方法用于创建已确定状态的 Promise。
Promise.resolve
// 创建一个已解决的 Promise
let cachedPromise = Promise.resolve(cachedData);
// 等同于
let cachedPromise = new Promise(resolve => resolve(cachedData));
使用场景:
- 确保函数总是返回 Promise
- 缓存已获取的数据
- 包装同步值为 Promise
Promise.reject
// 创建一个已拒绝的 Promise
let errorPromise = Promise.reject(new Error('失败'));
// 等同于
let errorPromise = new Promise((_, reject) => reject(new Error('失败')));
在现代代码中,这两个方法使用频率较低,因为有 async/await 语法糖。
总结对比表
| 方法 | 描述 | 成功条件 | 失败条件 |
|---|---|---|---|
Promise.all | 所有 Promise 成功 | 返回结果数组 | 任一失败立即拒绝 |
Promise.allSettled | 所有 Promise 完成 | 返回状态对象数组 | 不会拒绝 |
Promise.race | 第一个完成的 Promise | 可能成功或失败 | 可能成功或失败 |
Promise.any | 第一个成功的 Promise | 返回第一个成功结果 | 所有都失败才拒绝 |
Promise.resolve | 创建已解决的 Promise | 总是成功 | - |
Promise.reject | 创建已拒绝的 Promise | - | 总是失败 |
最佳实践建议
- 并行请求使用
Promise.all,但要考虑错误处理 - 需要完整结果时使用
Promise.allSettled - 超时控制使用
Promise.race - 备用方案优先使用
Promise.any - 避免过度使用
Promise.resolve/reject,优先使用 async/await
掌握这些 Promise API 的组合使用,可以让你在复杂异步场景下游刃有余,写出更健壮、更易维护的 JavaScript 代码。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



