async/await 实现
描述
async/await 是 ES2017 引入的异步编程语法糖,让异步代码看起来像同步代码。async 函数返回一个 Promise,await 用于等待一个 Promise 完成。
async/await 原理
- async:将普通函数包装成返回 Promise 的函数
- await:暂停 async 函数执行,等待 Promise resolve 后继续
- 编译器/解释器会将 async/await 编译成生成器 + Promise 的形式
手写实现
简易版 co 函数
js
function co(generator) {
const gen = generator();
return new Promise((resolve, reject) => {
function step(method, arg) {
try {
const result = gen[method](arg);
if (result.done) {
resolve(result.value);
} else {
Promise.resolve(result.value).then(
(val) => step("next", val),
(err) => step("throw", err),
);
}
} catch (err) {
reject(err);
}
}
step("next");
});
}使用生成器模拟 async/await
js
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve("data"), 100);
});
}
function fetchMore() {
return new Promise((resolve) => {
setTimeout(() => resolve("more"), 100);
});
}
// 使用生成器 + co 模拟 async/await
co(function* () {
const data = yield fetchData();
console.log(data); // 'data'
const more = yield fetchMore();
console.log(more); // 'more'
return "complete";
}).then(console.log); // 'complete'async 函数的实现
简易版 async
js
function myAsync(generatorFn) {
return function (...args) {
const generator = generatorFn.apply(this, args);
return co(generator);
};
}
// 使用
const asyncFn = myAsync(function* () {
const data = yield Promise.resolve(1);
const more = yield Promise.resolve(data + 2);
return more;
});
asyncFn().then(console.log); // 3带错误处理的完整版
js
class AsyncFunction {
constructor(generatorFn) {
this.generatorFn = generatorFn;
}
then(onFulfilled, onRejected) {
const self = this;
return new Promise(function (resolve, reject) {
function step(method, arg) {
try {
const result = self.generatorFn[method](arg);
if (result.done) {
Promise.resolve(result.value).then(resolve, reject);
} else {
Promise.resolve(result.value).then(
(val) => step("next", val),
(err) => step("throw", err),
);
}
} catch (err) {
reject(err);
}
}
step("next");
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
function async(generatorFn) {
return function (...args) {
return new AsyncFunction(generatorFn.apply(this, args));
};
}实际应用示例
顺序执行
js
// async/await 写法
async function fetchAll() {
const a = await fetchA();
const b = await fetchB();
const c = await fetchC();
return [a, b, c];
}
// 用生成器模拟
co(function* () {
const a = yield fetchA();
const b = yield fetchB();
const c = yield fetchC();
return [a, b, c];
});并行执行
js
// async/await 并行写法
async function fetchAllParallel() {
const [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()]);
return [a, b, c];
}
// 用生成器模拟
co(function* () {
const [a, b, c] = yield Promise.all([fetchA(), fetchB(), fetchC()]);
return [a, b, c];
});面试追问点
async/await 与 Promise 的关系
- async 函数始终返回 Promise
- await 后面通常是 Promise,也可以是任何值
- async/await 是 Promise 的语法糖,不能替代 Promise
async/await 的优点
- 代码更简洁、可读性更强
- 调试友好(可以在 await 处打断点)
- 错误处理统一(try/catch)
async/await 的缺点
- 错误处理不直观(容易忘记 try/catch)
- 并行执行需要配合 Promise.all
- 浏览器兼容性问题(需要转译)