如何利用promise + 生成器实现async/await ?

async / await 使用

  1. async函数返回一个 Promise 对象,async函数内部return语句返回的值,会成为then方法回调函数的参数。

  2. 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

  3. await 后面跟的是一个 Promise 对象,如果不是,则会包裹一层 Promise.resolve()

async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里,简而言之,就是 Generator 函数的语法糖。

Generator函数是什么?

  1. function关键字与函数名之间有一个星号;
  2. 函数体内部使用yield表达式,定义不同的内部状态

Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。

yield表达式就是暂停标志。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

// generator函数基本用法
function* generator() {
yield 1;
yield 2;
yield 3;
return 4;
}
const self = generator();
console.log(self.next()); //{ value: 1, done: false }
console.log(self.next()); //{ value: 2, done: false }
console.log(self.next()); //{ value: 3, done: false }
console.log(self.next()); //{ value: 4, done: true }
//如果不写return 则调用第四次self.next()为{ value: undefined, done: true}
//generator+promise使用
function* generator() {
yield Promise.resolve("1");
yield Promise.resolve("2");
yield Promise.resolve("3");
return Promise.resolve("4");
}
const self = generator();
const next1 = self.next();
next1.value.then((res1) => {
console.log(res1);
const next2 = self.next();
next2.value.then((res2) => {
console.log(res2);
//...往下推
});
});
//1,2

async / await 实现原理

  1. 封装一个函数, 接收一个生成器函数作为参数, 该函数返回一个 Promise 对象
  2. 首先调用生成器函数, 获取生成器对象
  3. 我们需要自动执行生成器函数的每一步, 我们再封装一个 step 函数, 传入一个匿名函数作为参数, 并执行生成器函数, 用来获取生成器函数中下一个 yield 表达式的值, 直到 next.done 为 true 或者 抛出了错误.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
async function fn(args) {
// ...
}
// 等同于下面代码
function fn(args) {
return spawn(function* () {});
}


function spawn(genFn) { // spawn 函数接受一个生成器函数 genFn 作为参数,该函数返回一个新的 Promise 对象。
return new Promise((resolve, reject) => {
const gen = genFn(); // 获取生成器对象
function step(nextFn) { // 用于执行生成器函数中的每一步。
let next;
try {
next = nextFn(); // 通过调用 nextFn() 来获取生成器函数中下一个 yield 表达式的值
} catch (e) {
return reject(e);
}
if (next.done) { // 如果 next.done 为 true,表示生成器函数执行完毕
return resolve(next.value);
}
Promise.resolve(next.value).then(
function (v) {
step(function () {
// 如果 Promise 成功,则调用 step 函数并传入一个匿名函数,该匿名函数调用 gen.next(v) 继续执行生成器函数。
return gen.next(v);
});
},
function (e) {
step(function () {
// 如果 Promise 失败,则调用 step 函数并传入一个匿名函数,该匿名函数调用 gen.throw(e) 将异常抛给生成器函数。
return gen.throw(e);
});
}
);
}
step(function () {
return gen.next(undefined);
// 通过调用 step 函数并传入一个匿名函数 () => gen.next(undefined) 来开始执行生成器函数。
});
});
}

参考文章

  1. https://juejin.cn/post/7318083950856241162?searchId=20240407181153A8E8CE8B4E109415D8C7#heading-5

如何利用promise + 生成器实现async/await ?
http://example.com/2024/04/08/如何自己封装一个asyncawait/
作者
weirdo
发布于
2024年4月8日
更新于
2024年4月8日
许可协议