在 JavaScript 中,async/await 是处理异步操作的语法糖,其底层基于 Promise 和 Generator(生成器)。以下是它的核心原理和手写实现思路:
一、async/await的核心原理
- async 函数
- 返回一个 Promise,函数内部的值会被自动包装成 Promise。
- 若函数抛出错误,会返回 Promise.reject(error)。
- await 表达式
- 会暂停 async 函数的执行,等待一个 Promise 完成。
- 本质上是通过 Generator 的暂停/恢复机制 实现的,结合 Promise 的链式调用。
二、async/await与 Generator 的关系
原生 async/await 的实现可以简化为以下步骤:
- 将 async 函数转换为 Generator 函数(生成器)。
- 使用一个 自动执行器(如 co 库) 驱动 Generator 逐步执行,处理 yield 的 Promise。
- 通过递归调用 next() 方法,在 Promise 完成后恢复 Generator 的执行。
三、手写async函数实现
以下是一个简化版的 async 函数实现,模拟 async/await 的行为:
1. 手写asyncToGenerator函数
function asyncToGenerator(generatorFunc) {
return function (...args) {
const generator = generatorFunc.apply(this, args);
return new Promise((resolve, reject) => {
function step(key, arg) {
let result;
try {
result = generator[key](arg); // 执行 next/throw
} catch (error) {
return reject(error); // 捕获同步错误
}
const { value, done } = result;
if (done) {
return resolve(value); // 生成器执行完毕
} else {
return Promise.resolve(value).then(
val => step("next", val), // 递归处理下一个 yield
err => step("throw", err) // 处理错误
);
}
}
step("next"); // 启动生成器
});
};
}
2. 使用示例
// 定义一个 Generator 函数(模拟 async 函数)
function* mockAsyncFunc() {
try {
const data1 = yield fetchData1(); // 模拟 await
const data2 = yield fetchData2(data1);
return data2;
} catch (error) {
console.error("Caught error:", error);
}
}
// 转换为类似 async 的函数
const asyncFunc = asyncToGenerator(mockAsyncFunc);
// 调用
asyncFunc().then(result => {
console.log("Final result:", result);
});
四、关键步骤解析
- 创建 Generator 对象
通过 generatorFunc.apply(this, args) 创建生成器实例。 - 驱动执行(step 函数)
- step("next") 启动生成器,首次调用 generator.next()。
- 如果生成器 yield 一个 Promise,等待其完成后继续执行 step("next", val)。
- 如果 Promise 失败,调用 step("throw", err) 抛出错误。
- 错误处理
- 使用 try/catch 包裹生成器方法调用,捕获同步错误。
- 通过 Promise.resolve(value).then(...) 处理异步错误。
五、与原生async/await的区别
特性 | 原生 async/await | 手写实现(Generator + 执行器) |
语法 | 内置关键字,更简洁 | 需要手动编写 Generator 和执行器 |
错误处理 | 自动捕获同步/异步错误 | 需手动处理 try/catch 和 throw |
性能 | 引擎优化,性能更高 | 递归调用可能有额外开销 |
返回值 | 始终返回 Promise | 依赖执行器返回 Promise |
兼容性 | ES2017+ | 可在 ES6 环境中模拟 |
六、总结
- 核心原理:async/await 本质是 Generator + 自动执行器 的语法糖,通过暂停/恢复函数执行管理异步流程。
- 手写关键:将 Generator 的 yield 与 Promise 链式调用结合,递归驱动生成器执行。
- 实际应用:理解这一机制有助于深入掌握异步编程,但生产环境应直接使用 async/await。
通过手写实现,可以更直观地理解 async/await 的底层逻辑,但原生语法在性能和可读性上更具优势。