一、核心关联
-
共同目标:解决 JavaScript 异步编程问题,避免回调地狱。
-
演进关系:
- Promise 是基础,提供链式调用管理异步操作。
- Generator 通过暂停/恢复函数执行,为实现协程(Coroutine)提供可能。
- async/await 基于 Promise 和 Generator 的语法糖,进一步简化异步代码。
-
底层依赖:
async/await的实现依赖 Promise 和 Generator 的机制。Generator可结合 Promise 实现类似async/await的效果(需手动控制执行)。
二、核心区别
| 特性 | Promise | Generator | async/await |
|---|---|---|---|
| 语法特性 | .then() 链式调用 | function* 和 yield 关键字 | async 函数和 await 关键字 |
| 执行控制 | 自动执行,不可暂停 | 可暂停和恢复(手动调用 next()) | 自动执行,类似同步代码 |
| 错误处理 | .catch() 捕获链式错误 | 需手动处理 try/catch | 支持 try/catch 同步式错误处理 |
| 返回值 | 返回 Promise 对象 | 返回迭代器(Iterator) | 返回 Promise 对象 |
| 适用场景 | 单个或多个异步操作的链式管理 | 复杂流程控制(如惰性计算、协程) | 简化异步代码,使其更接近同步逻辑 |
| 代码可读性 | 链式调用易嵌套,复杂场景可读性下降 | 需手动管理迭代器,代码较繁琐 | 代码扁平化,可读性最高 |
三、代码示例对比
1. Promise(链式调用)
fetchData()
.then(data => processData(data))
.then(result => saveResult(result))
.catch(err => console.error(err));
2. Generator(需手动控制执行)
function* asyncGenerator() {
try {
const data = yield fetchData();
const result = yield processData(data);
yield saveResult(result);
} catch (err) {
console.error(err);
}
}
// 手动执行 Generator
const gen = asyncGenerator();
gen.next().value
.then(data => gen.next(data).value)
.then(result => gen.next(result));
3. async/await(自动执行)
async function asyncTask() {
try {
const data = await fetchData();
const result = await processData(data);
await saveResult(result);
} catch (err) {
console.error(err);
}
}
四、关键区别详解
1. 执行机制
- Promise:一旦创建便立即执行,无法暂停。
- Generator:通过
yield暂停执行,需外部调用next()恢复。 - async/await:自动执行,
await会暂停当前async函数的执行,直到 Promise 完成。
2. 错误处理
- Promise:依赖
.catch()或链式中的第二个then参数。 - Generator:需在函数内部用
try/catch包裹yield。 - async/await:直接使用
try/catch捕获同步和异步错误。
3. 适用场景
- Promise:适合简单异步任务链,如接口顺序调用。
- Generator:适合需要精细控制执行流程的场景(如分批加载数据、状态机)。
- async/await:适合复杂异步逻辑,尤其是多依赖的异步操作(如事务性操作)。
五、三者的协作关系
1. Generator + Promise = 类 async/await
通过工具库(如 co)可自动执行 Generator,模拟 async/await 的行为:
const co = require('co');
co(function* () {
const data = yield fetchData();
return yield processData(data);
});
2. async/await 本质是 Generator 的语法糖
Babel 等工具会将 async/await 转换为 Generator + Promise 的实现。
3. Promise 是三者共同的基础
无论使用 Generator 还是 async/await,最终仍需依赖 Promise 处理异步结果。
六、如何选择?
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 简单异步链式调用 | Promise | 代码简洁,无需复杂语法 |
| 需要精细控制函数执行流程 | Generator | 手动暂停/恢复,适合协程或惰性计算 |
| 复杂异步逻辑,追求代码可读性 | async/await | 同步式写法,易于维护 |
| 兼容旧环境(不支持 ES2017+) | Promise + Generator | 通过 Polyfill 或工具库(如 co)实现 |
七、总结
- Promise:异步编程的基石,适合链式调用。
- Generator:提供函数暂停能力,适合复杂流程控制,但需手动管理。
- async/await:基于前两者的语法糖,简化异步代码,提升可读性。
演进关系:
Callback → Promise → Generator → async/await
选择建议:
- 现代项目中优先使用
async/await,必要时结合Promise.all等高级方法。 - 在需要底层控制或兼容旧环境时,可回归
Promise或Generator。