写点什么

【Promise 源码学习】第十七篇 - async/await 简介

作者:Brave
  • 2021 年 12 月 11 日
  • 本文字数:1947 字

    阅读完需:约 6 分钟

一,前言


上一篇,主要介绍了 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 生成器函数,内部自动执行完成,返回一个 promiseco(read()).then(data=>{ console.log(data); // 执行结果:c})
// 方法三:使用 async/awaitasync function read() { let data = await readFile('./a.txt','utf8'); data = await readFile(data,'utf8'); return data;}
// async 函数执行完成后,返回一个 promiseread().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[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 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;

用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【Promise 源码学习】第十七篇 - async/await 简介