一道打印程序引发的血案
异步编程是 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