#yyds干货盘点#【Promise 源码学习】第十七篇 - async/await 简介
一,前言
上一篇,主要介绍了 co 库的使用和实现原理,主要涉及以下几个点:
[*]co 库的简介:特性、用法、功能分析;
[*]co 库的实现和原理分析;
本篇,继续介绍 async/await:
[*]async/await 是基于 generator 的语法糖
[*]async/await 是 generator + co 的组合;
[*]async/await 是“回调地狱”问题的终极解决方案;
二,async/await 的使用
[*]测试场景:读取 a.txt得到结果 b.txt;读取 b.txt得到结果 c;
const util = require('util');
const fs = require('fs');
let readFile = util.promisify(fs.readFile)
// generator 生成器函数
function * read() {
let data = yield readFile('./a.txt','utf8');
data = yield readFile(data,'utf8');
return data;
}
// 方法一:Generator 生成器
let it = read(); // 生成器函数返回一个 Iterator 迭代器对象
let {value:v1, done:d1} = it.next(); // 注意:第一个next传参是无效的
v1.then(data=>{
console.log(data) // b.txt
let {value:v2, done:d2} = it.next(data); // 将第一次的结果作为第二次的入参
return v2
}).then(data=>{
console.log(data) // 执行结果:c
})
// 方法二:使用 co 库
const co = require('co')
// co 方法:包装 generator 生成器函数,内部自动执行完成,返回一个 promise
co(read()).then(data=>{
console.log(data);// 执行结果:c
})
// 方法三:使用 async/await
async function read() {
let data = await readFile('./a.txt','utf8');
data = await readFile(data,'utf8');
return data;
}
// async 函数执行完成后,返回一个 promise
read().then(data=>{
console.log(data)
})之前,使用 generator + co 组合,已经让代码看上去很像是同步了,但仍需要 co 库的支持;使用 async/await:在外层 function 前添加 async;await 右侧的方法返回 promise;无需 co 库支持即可实现;这样,代码看上去与“同步编码”无任何明显差异,有效避免了嵌套回调问题;
三,async/await 的实现
还是将 async/await 代码放入 babel.io,查看编译后的代码:
"use strict";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen(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 read() {
return _read.apply(this, arguments);
}
function _read() {
_read = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
var data;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return readFile('./a.txt', 'utf8');
case 2:
data = _context.sent;
_context.next = 5;
return readFile(data, 'utf8');
case 5:
data = _context.sent;
return _context.abrupt("return", data);
case 7:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return _read.apply(this, arguments);
}以上代码可以看出,_read函数就是之前实现的 generator 函数,这就说明 async 最终会被转换成为 generator 生成器;执行过程分析:
[*]第一次调用异步迭代方法,传入 undefined:_next(undefined);,进入asyncGeneratorStep方法:gen 是 it 迭代器,key 是 next 方法;
[*]如果没完成,继续调用_next(递归),继续取出下一个执行异步迭代;
所以,async/await 其实也就是 generator + co 的语法糖;编码中,所有异步回调代码可以全部采用 async/await 写法替换,可以有效解决回调嵌套问题;
四,结尾
本篇,主要介绍了 async/await 的使用和实现原理,主要涉及以下几个点:
[*]async/await 的使用和功能分析;
[*]async/await 的实现和原理分析;
下一篇,继续介绍浏览器的事件环 EventLoop;
https://blog.51cto.com/u_7466756/4847010
页:
[1]