时间:2021-05-26
async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解决方案。目前,async / await这个特性已经是stage 3的建议,可以看看TC39的进度,本篇文章将分享async / await是如何工作的,阅读本文前,希望你具备Promise、generator、yield等ES6的相关知识。
在详细介绍async / await之前,先回顾下目前在ES6中比较好的异步处理办法。下面的例子中数据请求用Node.js中的request模块,数据接口采用Github v3 api文档提供的repo代码仓库详情API作为例子演示。
Promise对异步的处理
虽然Node.js的异步IO带来了对高并发的良好支持,同时也让“回调”成为灾难,很容易造成回调地狱。传统的方式比如使用具名函数,虽然可以减少嵌套的层数,让代码看起来比较清晰。但是会造成比较差的编码和调试体验,你需要经常使用用ctrl + f去寻找某个具名函数的定义,这使得IDE窗口经常上下来回跳动。使用Promise之后,可以很好的减少嵌套的层数。另外Promise的实现采用了状态机,在函数里面可以很好的通过resolve和reject进行流程控制,你可以按照顺序链式的去执行一系列代码逻辑了。下面是使用Promise的一个例子:
const request = require('request');// 请求的url和headerconst options = { url: 'https://api.github.com/repos/cpselvis/zhihu-crawler', headers: { 'User-Agent': 'request' }};// 获取仓库信息const getRepoData = () => { return new Promise((resolve, reject) => { request(options, (err, res, body) => { if (err) { reject(err); } resolve(body); }); });};getRepoData() .then((result) => console.log(result);) .catch((reason) => console.error(reason););// 此处如果是多个Promise顺序执行的话,如下:// 每个then里面去执行下一个promise// getRepoData()// .then((value2) => {return promise2})// .then((value3) => {return promise3})// .then((x) => console.log(x))不过Promise仍然存在缺陷,它只是减少了嵌套,并不能完全消除嵌套。举个例子,对于多个promise串行执行的情况,第一个promise的逻辑执行完之后,我们需要在它的then函数里面去执行第二个promise,这个时候会产生一层嵌套。另外,采用Promise的代码看起来依然是异步的,如果写的代码如果能够变成同步该多好啊!
Generator对异步的处理
谈到generator,你应该不会对它感到陌生。在Node.js中对于回调的处理,我们经常用的TJ / Co就是使用generator结合promise来实现的,co是coroutine的简称,借鉴于python、lua等语言中的协程。它可以将异步的代码逻辑写成同步的方式,这使得代码的阅读和组织变得更加清晰,也便于调试。
const co = require('co');const request = require('request');const options = { url: 'https://api.github.com/repos/cpselvis/zhihu-crawler', headers: { 'User-Agent': 'request' }};// yield后面是一个生成器 generatorconst getRepoData = function* () { return new Promise((resolve, reject) => { request(options, (err, res, body) => { if (err) { reject(err); } resolve(body); }); });};co(function* () { const result = yield getRepoData; // ... 如果有多个异步流程,可以放在这里,比如 // const r1 = yield getR1; // const r2 = yield getR2; // const r3 = yield getR3; // 每个yield相当于暂停,执行yield之后会等待它后面的generator返回值之后再执行后面其它的yield逻辑。 return result;}).then(function (value) { console.log(value);}, function (err) { console.error(err.stack);});async / await对异步的处理
虽然co是社区里面的优秀异步解决方案,但是并不是语言标准,只是一个过渡方案。ES7语言层面提供async / await去解决语言层面的难题。目前async / await 在 IE edge中已经可以直接使用了,但是chrome和Node.js还没有支持。幸运的是,babel已经支持async的transform了,所以我们使用的时候引入babel就行。在开始之前我们需要引入以下的package,preset-stage-3里就有我们需要的async/await的编译文件。
无论是在Browser还是Node.js端都需要安装下面的包。
这里推荐使用babel官方提供的require hook方法。就是通过require进来后,接下来的文件进行require的时候都会经过Babel的处理。因为我们知道CommonJs是同步的模块依赖,所以也是可行的方法。这个时候,需要编写两个文件,一个是启动的js文件,另外一个是真正执行程序的js文件。
启动文件index.js
require('babel-core/register');require('./async.js');真正执行程序的async.js
const request = require('request');const options = { url: 'https://api.github.com/repos/cpselvis/zhihu-crawler', headers: { 'User-Agent': 'request' }};const getRepoData = () => { return new Promise((resolve, reject) => { request(options, (err, res, body) => { if (err) { reject(err); } resolve(body); }); });};async function asyncFun() { try { const value = await getRepoData(); // ... 和上面的yield类似,如果有多个异步流程,可以放在这里,比如 // const r1 = await getR1(); // const r2 = await getR2(); // const r3 = await getR3(); // 每个await相当于暂停,执行await之后会等待它后面的函数(不是generator)返回值之后再执行后面其它的await逻辑。 return value; } catch (err) { console.log(err); }}asyncFun().then(x => console.log(`x: ${x}`)).catch(err => console.error(err));注意点:
其实,async / await的用法和co差不多,await和yield都是表示暂停,外面包裹一层async 或者 co来表示里面的代码可以采用同步的方式进行处理。不过async / await里面的await后面跟着的函数不需要额外处理,co是需要将它写成一个generator的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
前言虽然大家知道async/await,但是很多人对这个方法中内部怎么执行的还不是很了解,本文是我看了一遍技术博客理解JavaScript的async/awai
众所周知C#提供Async和Await关键字来实现异步编程。在本文中,我们将共同探讨并介绍什么是Async和Await,以及如何在C#中使用Async和Awai
前言本文带你快速了解@Async注解的用法,包括异步方法无返回值、有返回值,最后总结了@Async注解失效的几个坑。在SpringBoot应用中,经常会遇到在一
本文实例讲述了ES6新特性之async函数用法。分享给大家供大家参考,具体如下:1.async函数是什么?node.js版本7及之后版本才支持该函数。可以简单的
javascript中$(function(){....})是jQuery中的经典用法,等同于$(document).ready(function(){....