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