🔥 Promise
Promise 是一个“未来值”的状态机 + 异步回调容器。
主要做三件大事:
- 把异步结果封进一个对象(pending → fulfilled/rejected)
- 状态只能单向流转
- 所有回调(then/catch)都被塞进 microtask 队列执行
所以 Promise 并不是“执行异步”,而是“组织和调度异步”。
⚠️ Promise 常见踩坑
❌ 1. 链式没有自动中断
Promise.resolve()
.then(() => { throw new Error('oops') })
.then(() => console.log('still?'))
要想中断链式调用,必须 return rejected promise
❌ 2. then 的 return ≠ 外层函数 return
function a() {
return Promise.resolve().then(() => 123)
}
console.log(a()) // 打印的永远是 Promise
❌ 3. await 写法不一定并发
await foo();
await bar(); // → 并没有并发,纯串行
正确并发:
await Promise.all([foo(), bar()]);
❌ 4. Promise 内 throw 与外部 throw 不是一回事
内部 throw → rejected
外部 throw → 程序直接炸
⚡ async/await
async/await = 用同步语法包装异步逻辑。 底层仍然是 Promise + microtask。
具体来说:
- async 会把返回值自动包成 Promise
- await 会“暂停”当前 async 函数,把后续拆成 then
- 并不会阻塞线程,只是代码被拆开
- async/await 不改变事件循环本质
⚠️ async/await 的常见踩坑
❌ 1. await 会让并发变串行
await foo();
await bar();
❌ 2. await 不会自动捕获异常
await Promise.reject('err'); // 不 try/catch 会直接抛
❌ 3. async 函数返回的一定是 Promise
async function a() { return 1; }
❌ 4. forEach + await = 陷阱现场
arr.forEach(async item => { await do(item); });
→ forEach 不会等你。
正确写法:
顺序执行:
for (const item of arr) await do(item);
并行执行:
await Promise.all(arr.map(do));
🎯 两者的区别
| 维度 | Promise | async/await |
|---|---|---|
| 风格 | 链式回调 | 同步化写法 |
| 本质 | 状态机 + 回调队列 | Promise 语法糖 |
| 错误处理 | then/catch | try/catch |
| 可读性 | 容易嵌套 | 清晰直观 |
| 并发 | Promise.all/race | 仍需配合 Promise |
| 堆栈 | 更碎 | 更连续 |
Promise 解决异步结果表达;async/await 解决异步写法难看。
Promise 是底层机制,async/await 是表现形式
异步世界里,它俩谁都离不开谁。