async 异步
async 函数是 ES2017 标准引入的,其与 await 语法搭配,用来更优雅地实现异步编程。与 generator 函数作用类似。不同的是,async 不需要手动调用 next 方法,并且返回值始终是 Promise 对象。
async 函数可以看作多个异步操作,包装成的一个 Promise 对象,而 await 命令就是内部 then 命令的语法糖。
async function asyncPrint() {
await new Promise((resolve) => {
setTimeout(()=>{
resolve(2);
console.log(1);
}, 1000);
})
console.log(2);
}
asyncPrint();// 1 2
实现原理
async 异步是由 generator 函数 + Promise 函数实现的。
以上 asyncPrint 方法在 babel 官网 解析成 ES5 语法如下:
"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;
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);
});
};
}
function asyncPrint() {
return _asyncPrint.apply(this, arguments);
}
function _asyncPrint() {
_asyncPrint = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return new Promise(function (resolve) {
setTimeout(function () {
resolve(2);
console.log(1);
}, 1000);
});
case 2:
console.log(2);
case 3:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return _asyncPrint.apply(this, arguments);
}
asyncPrint();
转换解析
以上代码中的 regeneratorRuntime 方法是 facebook 提供的 regenerator-runtime 模块中的。是提供生成器函数、async、await 函数经 babel 编译后的功能实现。模块内容可直接下载或百度。
- 以上代码中
regeneratorRuntime.mark
是将它的参数(参数是一个函数)转换为 generator 函数的函数。
regenerator-runtime 模块部分源码:
// 将传参genFun函数封装成生成器函数"GeneratorFunction",具体细节是
// __proto__属性设置为GeneratorFunctionPrototype,[toStringTagSymbol]属性设为"GeneratorFunction"
// prototype属性设为Gp对象(迭代器原型),即Generator的prototype的原型,使genFun instanceof Generator返回真值
// 注:instanceof方法用于判断对象是否某构造函数的实例,就其本质通过判断该对象是否由构造函数的原型对象Object.create创建
runtime.mark = function(genFun) {
if (Object.setPrototypeOf) {
Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
} else {
genFun.__proto__ = GeneratorFunctionPrototype;
if (!(toStringTagSymbol in genFun)) {
genFun[toStringTagSymbol] = "GeneratorFunction";
}
}
genFun.prototype = Object.create(Gp);
return genFun;
};
- 以上代码中
_asyncToGenerator
返回了一个匿名函数,该匿名函数中返回一个 Promise 对象。 - 在该 Promise 对象中
gen
是 generator 函数的第一次调用。 - 继续调用 Promise 中的
_next
方法,_next
方法中又调用asyncGeneratorStep
方法。 - 在
asyncGeneratorStep
方法中,变量info
是第一次调用 next 得到的值。然后返回Promise.resolve
。resolve
中的参数也是一个 Promise。这一轮走了_callee$
方法中switch
中的case 0
。即打印出 1 。 - 继续 4-5 步,打印出 2。
- 直到
info
为{value:undefined,done:true}
,即执行完成。
总结
所以 async 异步函数就是通过 generator 函数的 next 方法控制一步步执行,然后每次执行完都返回一个 Promise 对象。