Skip to content
目录

async_await 自动执行器

代码如下,将async&await语法改为生成器函数和一个自动执行器函数

ts
async function asyncFunc(value) {
  return value;
}

async function printNum() {
  console.log(1);
  console.log(await asyncFunc(2));
  console.log(3);
}

// 目标代码
function asyncFunc(value) {
  return value;
}

function* () {
    console.log(1);
    console.log(yield asyncFunc(2));
    console.log(3);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

审题:

从题目中可知,console.log(3)会被放到微任务队列中执行我们考虑使用promise.then方法

已知async函数会被改为生成器函数,所以我们需要一个函数的执行器_executor(),这里采用了一个惰性函数,减少函数重复调用

ts
function asyncGeneratorStep() {}
// _asyncToGenerator方法会将生成器函数转化成一个自动执行的函数
function _asyncToGenerator() {}

function asyncFunc(value) {
  return value;
}

function _executor(...args) {
  _executor = _asyncToGenerator(function* () {
    console.log(1);
    console.log(yield asyncFunc(2));
    console.log(3);
  });
  return _executor.apply(this, args);
}

// 同样也修改printNum的调用
function printNum(...args) {
  return _executor.apply(this, args);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


接下来是重点的自动执行器

  • 由于我们采用了惰性函数,_asyncToGenerator函数的返回值会作为新的_executor函数,所以_asyncToGenerator函数也会返回一个函数
  • async函数的返回值是一个promise,所以这个返回的新函数也返回一个promise

理论成立,实践开始,自信且大胆的定义函数和返回值

ts
function _asyncToGenerator(fn) {
  return function (...args) {
    return new Promise((resolve, reject) => {});
  };
}
1
2
3
4
5


接下来创建generator对象,由于我们并非在和async函数相同的上下文中执行生成器,这里需要采用全局上下文

ts
function _asyncToGenerator(fn) {
  const self = this;
  return function (...args) {
    return new Promise((resolve, reject) => {
      const generator = fn.apply(self, args);
    });
  };
}
1
2
3
4
5
6
7
8


前面提过,await后面的语句会被放进微任务队列中执行,并且我们会采用promise.then方法来完成

这里还有一个逻辑,当生成器执行结束时会resolve这个promise,出现错误则会reject这个promise

为了代码整洁,我们把promise的兑现方法交给一个新的函数

ts
/**
 *
 * @param {*} generator 生成器对象
 * @param {*} resolve
 * @param {*} reject
 * @param {*} arg
 * @returns
 */
function asyncGeneratorStep(generator, resolve, reject, arg) {
  let info = null;
  try {
    info = generator.next(arg);
  } catch (error) {
    reject(error);
    return;
  }
  if (info?.done) {
    resolve(info?.value);
  } else {
    Promise.resolve(info?.value).then(/*微任务中执行下一次next()*/);
  }
}

function _asyncToGenerator(fn) {
  const self = this;
  return function (...args) {
    return new Promise((resolve, reject) => {
      const generator = fn.apply(self, args);
      asyncGeneratorStep(generator, resolve, reject, void 0);
    });
  };
}
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


在微任务中执行下一次next()方法,我们可以考虑递归的调用,这里的递归和同步递归不太相同,他将在微任务队列中加入下一次函数调用

ts
/**
 *
 * @param {*} generator 生成器对象
 * @param {*} resolve
 * @param {*} reject
 * @param {*} _next next方法
 * @param {*} _throw 抛错方法
 * @param {*} arg
 * @returns
 */
function asyncGeneratorStep(generator, resolve, reject, _next, _throw, arg) {
  let info = null;
  try {
    info = generator.next(arg);
  } catch (error) {
    reject(error);
    return;
  }
  if (info?.done) {
    resolve(info?.value);
  } else {
    Promise.resolve(info?.value).then(_next, _throw);
  }
}

function _asyncToGenerator(fn) {
  const self = this;
  return function (...args) {
    return new Promise((resolve, reject) => {
      const generator = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(generator, resolve, reject, _next, _throw, value);
      }
      function _throw(error) {
        asyncGeneratorStep(generator, resolve, reject, _next, _throw, error);
      }
      _next(void 0);
    });
  };
}
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

代码实现:

ts
function asyncGeneratorStep(generator, resolve, reject, _next, _throw, arg) {
  let info = null;
  try {
    info = generator.next(arg);
  } catch (error) {
    reject(error);
    return;
  }
  if (info?.done) {
    resolve(info?.value);
  } else {
    Promise.resolve(info?.value).then(_next, _throw);
  }
}

function _asyncToGenerator(fn) {
  const self = this;
  return function (...args) {
    return new Promise((resolve, reject) => {
      const generator = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(generator, resolve, reject, _next, _throw, value);
      }
      function _throw(error) {
        asyncGeneratorStep(generator, resolve, reject, _next, _throw, error);
      }
      _next(void 0);
    });
  };
}

function asyncFunc(value) {
  return value;
}

function printNum(...args) {
  return _executor.apply(this, args);
}

function _executor(...args) {
  _executor = _asyncToGenerator(function* () {
    console.log(1);
    console.log(yield asyncFunc(2));
    console.log(3);
  });
  return _executor.apply(this, args);
}

printNum();
console.log(4);
/**
 * 1 4 2 3
 */
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
44
45
46
47
48
49
50
51
52
53

Released under the MIT License.