【babel】babel如何编译async语法
2023/02/01 14:21:32
示例
const getData = () =>
new Promise((resolve) => setTimeout(() => resolve("data"), 1000));
async function test() {
const data = await getData();
console.log("data: ", data);
const data2 = await getData();
console.log("data2: ", data2);
return "success";
}
// 这样的一个函数 应该再1秒后打印data 再过一秒打印data2 最后打印success
test().then((res) => console.log(res));
babel 编译结果
原始编译代码
对于上面的示例,babel 编译结果如下(只节选关键内容):
function test() {
return _test.apply(this, arguments);
} // 这样的一个函数 应该再1秒后打印data 再过一秒打印data2 最后打印success
function _test() {
_test = _asyncToGenerator(
/*#__PURE__*/ _regeneratorRuntime().mark(function _callee() {
var data, data2;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1)
switch ((_context.prev = _context.next)) {
case 0:
_context.next = 2;
return getData();
case 2:
data = _context.sent;
console.log("data: ", data);
_context.next = 6;
return getData();
case 6:
data2 = _context.sent;
console.log("data2: ", data2);
return _context.abrupt("return", "success");
case 9:
case "end":
return _context.stop();
}
}, _callee);
})
);
return _test.apply(this, arguments);
}
整理编译代码
将上面编译后的代码调整成容易理解的样子:
function _test() {
fn1 = function _callee() {
var data, data2;
fn2 = function _callee$(_context) {
while (1)
switch ((_context.prev = _context.next)) {
case 0:
_context.next = 2;
return getData();
case 2:
data = _context.sent;
console.log("data: ", data);
_context.next = 6;
return getData();
case 6:
data2 = _context.sent;
console.log("data2: ", data2);
return _context.abrupt("return", "success");
case 9:
case "end":
return _context.stop();
}
};
return _regeneratorRuntime().wrap(fn2, _callee);
};
fn = /*#__PURE__*/ _regeneratorRuntime().mark(fn1);
_test = _asyncToGenerator(fn);
return _test.apply(this, arguments);
}
提取关键代码
function _test() {
fn1 = function _callee {
fn2 = function _callee$(_context) {
// ...
}
// ...
return _regeneratorRuntime().wrap(fn2, _callee);
};
fn = /*#__PURE__*/ _regeneratorRuntime().mark(fn1);
_test = _asyncToGenerator(fn);
return _test.apply(this, arguments);
}
要搞这段代码的逻辑需要了解这些问题:
_asyncToGenerator()
方法的作用。_regeneratorRuntime()
方法的作用,以及它返回的.wrap()
和.mark()
方法的作用。_callee()
、_callee$()
方法的作用。
async/await
的实现
babel 对 在 babel 编译后的代码中可以找到其定义:
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);
});
};
}
_asyncToGenerator(fn)
接收一个函数(看起来像是一个 Generator 函数),返回一个 Promise,具体操作由 asyncGeneratorStep()
方法执行,并由该方法决定这个 Promise 何时 resolve 或 reject。
asyncGeneratorStep()
方法分析:
/**
* @param gen _asyncToGenerator(fn) 中根据 Generator 函数(fn)生成的迭代器
* @param resolve _asyncToGenerator(fn) 返回值 Promise 的 resolve 方法
* @param reject _asyncToGenerator(fn) 返回值 Promise 的 reject 方法
* @param _next 接收一个参数,作为下一次调用 asyncGeneratorStep() 方法的 arg
* @param _throw 接收一个参数,作为下一次调用 asyncGeneratorStep() 方法的 arg
* @param key 'next' | 'throw' 用来标记本次需要调用 gen 的 .next() 还是 .throw()
* @param arg 迭代器上次迭代的返回值
*/
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
// 调用 gen 的 .next() 或 .throw() 方法,并将上次迭代的返回值传递下去
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);
}
}
可见 _asyncToGenerator()
和 asyncGeneratorStep()
其实就是对 async
和 await
的实现:_asyncToGenerator()
接收类似 Generator 的函数,并且一步步执行 yield 语句,最终返回一个 promise。