一道打印程序引发的血案

异步编程是 JS 中重要的模块,前几日逛 B 站,刷到这么一个发问,拿来钻研一下:

let promise1 = Promise.resolve()    .then(res => console.log(1))    .then(res => console.log(2))let promise2 = new Promise(resolve => {    setTimeout(() => {        console.log(6)        resolve()    })}).then(res => console.log(3))async function main() {    console.log(4)    console.log(await Promise.all([promise2, promise1]))    console.log(5)    return { obj: 5 }}let promise3 = Promise.resolve()    .then(res => console.log(8))    .then(res => console.log(9))console.log(typeof main())
变量对象申明

首先会创立变量对象,申明函数和变量,函数的申明优先级比变量高。会变成

VO = {  main: reference async function(){},  promise1: undefined,  promise2: undefined,  promise3: undefined,}

接下来 代码执行阶段,首先会对变量进行赋值:

对 promise1 来说:
Promise.resolve() 会立刻执行
then(res => console.log(1)).then... 会放入本轮的微工作

对 promise2 来说
开启一个 setTimeout 宏工作,之后的 then 会在宏工作完结后的 当次 微工作 中执行

对 promise3 来说:
Promise.resolve() 会立刻执行
then(res => console.log(8)).then... 会放入本轮的微工作

进入 main 函数:
执行 console.log(4) 
执行 console.log(await Promise.all([promise2, promise1])) 
这一步是整个函数最要害的中央。

async...await 执行程序

async...await 是 generator 的语法糖。实质是 generator + co 库,内置函数执行器。会主动执行每一个 yeild,把最初执行的后果通过 Promise resolve 的形式抛出。不便链式调用。
咱们把代码通过 babel 转译,能够看上面代码中正文的 1 、2 两个中央。

"use strict";function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {   try {     var info = gen[key](arg);     var value = info.value;   } catch (error) {     reject(error); return;   }   if (info.done) {     resolve(value);   } else {     Promise.resolve(value).then(_next, _throw);   } }function _asyncToGenerator(fn) {   return function () {     var self = this,     args = arguments;     // 2. 执行 async 首先返回一个 promise    // 返回之前会先执行完 Promise 外面的 executor 函数    return new Promise(function (resolve, reject) {       var gen = fn.apply(self, args);       function _next(value) {         asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);       }       function _throw(err) {         asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); }         _next(undefined);     });  }; }var promise1 = Promise.resolve().then(function (res) {  return console.log(1);}).then(function (res) {  return console.log(2);});var promise2 = new Promise(function (resolve) {  setTimeout(function () {    console.log(6);    resolve();  });}).then(function (res) {  return console.log(3);});function main() {    return _main.apply(this, arguments);}function _main() {  // 1. main 函数开始真正执行的是 _asyncToGenerator  _main = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {    // 3. regeneratorRuntime 函数来自 facebook 的 regenerator 模块,用来编译 generator 函数    // mark 函数为 指标函数的原型链上注入了 next、throw、return 等函数    // wrap 函数包装一层,把next 的调用指向内部的 context    // 这一步外围能够看 regenerator 源码    return regeneratorRuntime.wrap(function _callee$(_context) {      while (1) {        switch (_context.prev = _context.next) {          case 0:            console.log(4);            _context.t0 = console;            _context.next = 4;            return Promise.all([promise2, promise1]);          case 4:            _context.t1 = _context.sent;            _context.t0.log.call(_context.t0, _context.t1);            console.log(5);            return _context.abrupt("return", {              obj: 5            });          case 8:          case "end":            return _context.stop();        }      }    }, _callee);  }));  return _main.apply(this, arguments);}var promise3 = Promise.resolve().then(function (res) {  return console.log(8);}).then(function (res) {  return console.log(9);});console.log(typeof(main()));

期待 console.log(await Promise.all([promise2, promise1])) 执行完,这一行比拟有迷惑性,promise1 和 promise2 的执行后面曾经触发,此处只是等他们的异步全副执行完。
之后的执行就是同步操作了

自此残缺输入程序为:

 4'object' //async 函数返回 1 8 2 9 6 3[undefined, undefined] 5
regenerator

对于 regenerator 模块的参考资料,感兴趣的能够理解以下材料

1、https://www.iteye.com/blog/schifred-2369320
2、https://juejin.cn/post/6844903701908291592