如何用Generator和Promise实现async/await的功能
思考题
请将以下async/await
代码以另一种方式实现,保证异步等待功能和输出顺序一致:
function delay(ms, data) {
return new Promise(resolve => setTimeout(resolve, ms, data));
}
const func = async () => {
const data = await delay(2000, 'A');
console.log(data);
const res = await delay(2000, 'B');
console.log(res);
};
func();
在继续之前,可以先自己尝试实现一下。接下来我将从async/await
的基础知识开始介绍。
async/await 基本介绍
async/await
是基于Promise的语法糖,能让异步代码更加简洁易读,避免繁琐的Promise链式写法。
async 关键字
async
函数总是返回Promise,返回的结果可能是resolved
或rejected
状态。
resolved 情况:
- 如果函数有返回值,则该值被包装为
Promise.resolve
。 - 如果没有返回值,Promise中的值为
undefined
。
const func = async () => 1; console.log(func()); // 输出: Promise {<fulfilled>: 1}
- 如果函数有返回值,则该值被包装为
rejected 情况:
- 当函数返回或抛出错误时,Promise为
rejected
状态。
const func = async () => { throw new Error('error'); }; console.log(func()); // 输出: Promise {<rejected>: Error: error}
- 当函数返回或抛出错误时,Promise为
await 关键字
await
只能在async
函数内部使用,它用于等待Promise完成,并返回其结果。
resolved 情况:
const func = async () => { const data = await Promise.resolve('done'); console.log(data); // 输出: done };
rejected 情况:
如果Promise被拒绝(rejected)且没有捕获,会抛出错误。
const func = async () => { const data = await Promise.reject('error'); // 抛出错误 };
如何用Generator实现 async/await 功能
为了理解async/await
,我们可以借助Generator
实现类似的功能。Generator
是一种函数,可以在执行过程中暂停和恢复。我们通过yield
来控制执行的暂停和继续。
Generator 简介
function* generatorFunc() {
yield 1;
yield 2;
yield 3;
}
生成器函数返回一个迭代器对象,通过调用next()
方法逐步执行:
const iterator = generatorFunc();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
Generator 与 异步操作
我们可以利用Generator
和Promise
的结合来模拟async/await
的行为。以下是具体的实现思路:
function delay(ms, data) {
return new Promise(resolve => setTimeout(resolve, ms, data));
}
const func = function* () {
const data = yield delay(2000, 'A');
console.log(data);
const res = yield delay(2000, 'B');
console.log(res);
};
let it = func();
// 手动执行Promise链
it.next().value.then(res1 => {
it.next(res1).value.then(res2 => {
it.next(res2);
});
});
这种实现方式使用了Generator
来控制函数的暂停,并通过Promise来管理异步操作,从而实现与async/await
类似的效果。
总结
通过这一思考题,我们可以看出async/await
实际上是Generator
和Promise
的语法糖。理解这些原理有助于我们更好地掌握JavaScript的异步编程模型。