Promise 是现代 JavaScript 异步编程的基石。它让复杂的异步操作变得可读、可维护、可组合。
本文将系统讲解 Promise 的创建方式、核心方法(then/catch/all/race/finally) 和实际应用场景,助你彻底掌握这一关键技能。
一、创建 Promise 对象的三种方式
✅ 方式1:使用 new Promise()
最标准的方式,接收一个执行器函数(executor),该函数有两个参数:resolve 和 reject。
const myPromise = new Promise((resolve, reject) => {
// 同步代码立即执行
console.log('Promise 正在执行...');
// 模拟异步操作
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve('✅ 操作成功!');
} else {
reject(new Error('❌ 操作失败!'));
}
}, 1000);
});
resolve(value):将状态变为fulfilled,传递value;reject(error):将状态变为rejected,传递错误原因。
✅ 方式2:Promise.resolve(value)
快捷创建一个已成功的 Promise。
// 等价于 new Promise(resolve => resolve(42))
const p1 = Promise.resolve(42);
p1.then(value => {
console.log(value); // 42
});
使用场景:
- 返回已知结果的 Promise;
- 将非 Promise 值包装成 Promise(便于链式调用)。
✅ 方式3:Promise.reject(reason)
快捷创建一个已失败的 Promise。
// 等价于 new Promise((resolve, reject) => reject(new Error('Oops')))
const p2 = Promise.reject(new Error('请求超时'));
p2.catch(err => {
console.error(err.message); // 请求超时
});
二、实战示例:带条件的 Promise
function testPromise(ready) {
return new Promise((resolve, reject) => {
if (ready) {
resolve("Hello World!");
} else {
reject("No thanks");
}
});
}
// 调用
testPromise(true)
.then(
msg => console.log(msg), // 成功回调 → "Hello World!"
error => console.log(error) // 失败回调(可省略)
);
testPromise(false).catch(err => {
console.log(err); // "No thanks"
});
💡
.then()接收两个可选参数:onFulfilled和onRejected。
三、Promise 的五大核心方法
1️⃣ .then():处理成功与失败
.then() 是 Promise 最核心的方法,用于注册状态改变后的回调。
promise.then(
value => { /* fulfilled 回调 */ },
error => { /* rejected 回调 */ }
);
✅ 链式调用(串行异步任务)
// 串行请求:必须按顺序执行
ajax('first')
.then(res1 => {
console.log('第一请求完成:', res1);
return ajax('second'); // 返回新 Promise
})
.then(res2 => {
console.log('第二请求完成:', res2);
return ajax('third');
})
.then(res3 => {
console.log('第三请求完成:', res3);
})
.catch(err => {
console.error('任一请求失败:', err);
});
📌 关键点:
.then()返回新的 Promise,支持链式调用;- 返回值决定下一个
.then的行为(普通值、Promise、抛错)。
2️⃣ .catch():统一错误处理
.catch() 专门处理 rejected 状态,相当于 .then(null, onRejected)。
// 推荐写法:分离成功和失败处理
ajax('/api/data')
.then(data => {
console.log('数据:', data);
})
.catch(error => {
console.error('请求失败:', error.message);
});
🔥 强大功能:捕获链中任何错误
ajax('step1')
.then(() => {
throw new Error('中间出错');
})
.then(() => {
console.log('不会执行');
})
.catch(err => {
console.log('被捕获:', err.message); // 会执行
});
✅ 最佳实践:总是使用
.catch()或try/catch(async 函数中)来避免静默错误。
3️⃣ .all():并行执行,全成功才通过
Promise.all(iterable) 接受一个 Promise 数组,所有都成功才 resolve,任一失败则 reject。
const p1 = new Promise(resolve => setTimeout(() => resolve(1), 2000));
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
const p3 = new Promise(resolve => setTimeout(() => resolve(3), 3000));
Promise.all([p1, p2, p3])
.then(results => {
console.log(results); // [1, 2, 3] —— 按数组顺序返回
})
.catch(err => {
console.error('任一请求失败:', err);
});
✅ 实际应用:并发请求
// 同时加载用户、文章、评论
Promise.all([
fetch('/api/user'),
fetch('/api/posts'),
fetch('/api/comments')
]).then(([userRes, postsRes, commentsRes]) => {
return Promise.all([
userRes.json(),
postsRes.json(),
commentsRes.json()
]);
}).then(([user, posts, comments]) => {
console.log({ user, posts, comments });
});
4️⃣ .race():竞速模式,谁快用谁
Promise.race(iterable) 返回第一个完成的 Promise 的结果。
const p1 = new Promise((_, reject) => setTimeout(() => reject(1), 2000));
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
const p3 = new Promise(resolve => setTimeout(() => resolve(3), 3000));
Promise.race([p1, p2, p3])
.then(result => {
console.log(result); // 2 —— p2 最快
})
.catch(err => {
console.log('最快的是 reject:', err);
});
✅ 实际应用:设置超时
function timeout(ms) {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error('请求超时')), ms);
});
}
Promise.race([
fetch('/api/slow-data'),
timeout(5000) // 5秒后超时
])
.then(response => response.json())
.catch(err => console.error('Error:', err.message)); // 可能是网络错误或超时
5️⃣ .finally():无论成败,都要执行
.finally() 指定最终一定会执行的操作,常用于清理资源。
let loading = true;
fetch('/api/data')
.then(res => res.json())
.then(data => {
console.log(data);
})
.catch(err => {
console.error(err);
})
.finally(() => {
loading = false; // 关闭加载动画
console.log('请求结束');
});
🔍 重要特性
- 不接收参数:无法知道前面是成功还是失败;
- 不影响结果:
finally中的返回值被忽略; - 等价于:
promise.then(
result => { /* 操作 */; return result; },
error => { /* 操作 */; throw error; }
);
四、其他静态方法(ES2020+)
| 方法 | 说明 |
|---|---|
Promise.allSettled() | 等待所有 Promise 结束,返回结果数组(包含 status 和 value/reason) |
Promise.any() | 第一个 fulfilled 的 Promise 决定结果;全部 reject 才 reject |
✅ 示例:Promise.allSettled
const promises = [
fetch('/api/user').catch(() => 'Failed'),
fetch('/api/posts').catch(() => 'Failed')
];
Promise.allSettled(promises).then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`请求 ${index} 成功:`, result.value);
} else {
console.log(`请求 ${index} 失败:`, result.reason);
}
});
});
五、总结:Promise 方法对比表
| 方法 | 用途 | 成功条件 | 失败条件 |
|---|---|---|---|
.then() | 链式处理异步 | 上一个 resolve | 上一个 reject 或抛错 |
.catch() | 错误处理 | - | 捕获链中任一错误 |
.all() | 并行,全成功 | 所有 fulfilled | 任一 rejected |
.race() | 竞速 | 第一个 fulfilled | 第一个 rejected |
.allSettled() | 全部结束 | 总是成功,返回结果数组 | 不会 reject |
.any() | “或”逻辑 | 第一个 fulfilled | 所有 rejected |
.finally() | 清理操作 | 传递原结果 | 传递原错误 |
💡 结语
“掌握
Promise的五种方法,就掌握了现代异步编程的钥匙。”
- 用
.then()处理成功; - 用
.catch()统一错误; - 用
.all()并发执行; - 用
.race()设置超时; - 用
.finally()清理资源。
这些方法让你的异步代码更健壮、更高效、更易读。