所属板块:4. 异步编程与事件循环
记录日期:2026-03-xx
更新:遇到 Promise 输出题或手写题时补充
1. 回调函数(Callback)的时代与痛点
最早的异步方案就是回调函数:
fs.readFile('file.txt', (err, data) => {
// 处理数据
});
两大致命痛点:
- 回调地狱(Callback Hell):代码向右横向发展,层层嵌套,难以阅读和维护
- 控制反转:回调函数的执行权交给第三方(比如 AJAX 库),信任缺失,错误处理非常麻烦
这就是 Promise 诞生的背景——它把“回调”变成了“可链式操作的对象”。
2. Promise 的基础与规范(Promises/A+)
Promise 有三种且只能三种状态(单向不可逆):
- pending(进行中,默认状态)
- fulfilled / resolved(成功)
- rejected(失败)
关键边界:
new Promise(executor)中的 executor 函数是同步立即执行的.then()/.catch()的回调是异步的(推入微任务队列,见 [4-1])
new Promise((resolve, reject) => {
console.log("1"); // 同步
resolve("success");
}).then(res => {
console.log("2"); // 微任务,后执行
});
console.log("3");
输出:1 → 3 → 2
3. 链式调用(Chaining)与值穿透
.then() 必须返回一个新的 Promise,实现链式调用:
Promise.resolve(1)
.then(res => res * 2) // 返回新 Promise
.then(res => res + 3)
.then(res => console.log(res)); // 5
值穿透(重要):
如果 .then() 传入的不是函数(比如 .then(123)),值会直接透传给下一个 .then()。
异常穿透:
任何 .then() 中抛出错误或返回 rejected 的 Promise,都会直接跳到后面的 .catch()。
4. Promise 核心 API 对比与实战场景
| API | 特点 | 适用场景 | 失败处理方式 |
|---|---|---|---|
Promise.all | 全部成功才成功,顺序保持原数组 | 并发请求所有数据 | 一个失败就整体失败 |
Promise.race | 谁先完成听谁的 | 请求超时控制 | 最快的一个决定状态 |
Promise.allSettled | 无论成功失败都返回所有结果(ES2020) | 相互独立的批量操作 | 不短路 |
Promise.any | 只要有一个成功就成功(ES2021) | 多节点容灾请求 | 全部失败才失败 |
Promise.resolve/reject | 快速创建已决的 Promise | 统一返回格式 | - |
示例(并发控制经典写法):
// 并发请求 + 保持结果顺序
const urls = ['/api1', '/api2', '/api3'];
Promise.all(urls.map(url => fetch(url)))
.then(responses => Promise.all(responses.map(r => r.json())))
.then(data => console.log(data));
5. 小结 & 复习时的“演进视角”
- 回调 → Promise 解决了“地狱”和“控制反转”两大问题
- 核心是状态机 + 微任务调度(结合 [4-1] 的事件循环理解)
- 掌握了 Promise 的链式调用和静态 API,async/await 的底层就很好理解了
下一篇文章会进入 [4-3]:终极异步解决方案(Generator + async/await 的本质、await 在 Event Loop 中的表现、并发优化与错误处理)。
返回总目录:戳这里