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端都需要安装下面的包。

$ npm install babel-core --save$ npm install babel-preset-es2015 --save$ npm install babel-preset-stage-3 --save

这里推荐使用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则是进行执行顺序控制,每次执行一个await,程序都会暂停等待await返回值,然后再执行之后的await。

  • await后面调用的函数需要返回一个promise,另外这个函数是一个普通的函数即可,而不是generator。

  • await只能用在async函数之中,用在普通函数中会报错。

  • await命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中。

其实,async / await的用法和co差不多,await和yield都是表示暂停,外面包裹一层async 或者 co来表示里面的代码可以采用同步的方式进行处理。不过async / await里面的await后面跟着的函数不需要额外处理,co是需要将它写成一个generator的。

转载于:https://blog.51cto.com/12902932/1925694

Javascript中的async await相关推荐

  1. promise用法_JavaScript中的async/await的用法和理解

    昨天更新的是"JavaScript中的Promise使用详解",其实也就是说了下基本用法和自己对Promise的理解,可能有错误之处,也欢迎指出.今天就说一说"JavaS ...

  2. 在.NET中执行Async/Await的两种错误方法

    微信公众号:架构师高级俱乐部 关注可了解更多的编程,架构知识.问题或建议,请公众号留言; 如果你觉得此文对你有帮助,欢迎转发 在.NET中执行异步/等待的两种错误方法 在应用开发中,我们为了提高应用程 ...

  3. 【vue】---vue中使用async+await出现的问题及解决方案

    [vue]---vue中使用async+await出现的问题及解决方案 参考文章: (1)[vue]---vue中使用async+await出现的问题及解决方案 (2)https://www.cnbl ...

  4. 循环中使用async/await

    此需求在于二次循环中需要使用async/await,按照每次嵌套循环的时候,进行async,则会给出错误的输出,如下所示 let list = [{name: "a",age: 1 ...

  5. Microsoft.Bcl.Async 使用总结--在.NET Framework 4.5项目上使用.NET Framework 4.5版本及以上版本才可以使用C# 5中的async/await异步特

    正常情况下async/await异步特性,只能在.NET Framework 4.5以上的版本才可以使用,那如果想在.NET Framework 4使用C# 5中的异步特性怎么办呢?还好有一个开源的类 ...

  6. 实际案例:在现有代码中通过async/await实现并行

    实际案例:在现有代码中通过async/await实现并行 一项新技术或者一个新特性,只有你用它解决实际问题后,才能真正体会到它的魅力,真正理解它.也期待大家能够多分享解一些解决实际问题的内容. 在我们 ...

  7. 如何在 JavaScript 循环中使用 async/await

    在循环中迭代循环项和处理异步逻辑(即API调用),可能是我们作为JavaScript开发人员必须执行的两个最常见的任务.本文将讨论的是组合async/await和迭代逻辑的最佳方法. 有时候,你会希望 ...

  8. 为何在 JavaScript 中使用顶层 await?

    原文地址:Why Should You Use Top-level Await in JavaScript?[1] 原文作者:Mahdhi Rezvi[2] 译者:Chor 作为一门非常灵活和强大的语 ...

  9. vue 表格中有列需要异步加载_Vue中使用async/await解决异步请求问题

    1.async/await场景 用同步的思维来解决异步问题,当前端接口调用需要等到接口返回值以后渲染页面. 2.名词解释 async async的用法,它作为一个关键字放到函数前面,用于表示函数是一个 ...

最新文章

  1. MikuMikuDance 6 菜单汉化补丁
  2. Hessian RPC示例和基于Http请求的Hessian序列化对象传输
  3. mysql os.pid_离线安装Mysql
  4. Docker-tag
  5. Spring 配置解析之Properties
  6. 2017年第八届蓝桥杯C/C++ A组国赛 —— 第三题:表达式计算
  7. 【Linux】一步一步学Linux——ac命令(102)
  8. 机器学习变量转换(定性变量、定量变量)
  9. NUMPY数据集练习 ----------SKLEARN类
  10. [转]oracle分析函数Rank, Dense_rank, row_number
  11. MyBatis嵌套查询解析
  12. 复盘模型_组织内如何进行经验萃取复盘
  13. MCGS 无限配方数据存储及U盘导入导出-第一集
  14. 普通程序员想转人工智能,不知道它?别想了!
  15. Vue实例-本地留言板
  16. 对软件开发感到惊讶的共识
  17. Android JNI开发笔记二:动态库和静态库
  18. 计算机怎么在表格里打勾,怎样在Excel输入对号√,Excel单元格怎么输入对号(方框内打勾)?...
  19. oracle百度坐标系火星转换,标准坐标系与火星坐标系(高德)百度坐标系之间互转...
  20. python实现的EDF(earliest deadline first)算法

热门文章

  1. 【HDOJ】2732 Leapin' Lizards
  2. Vs2013 头文件注释
  3. android 解析雅虎天气
  4. Play 2.0 用户指南 - 使用JSON库 -- 针对Scala开发者
  5. 隐藏帐户与隐藏权限的添加
  6. 细看CRLF注入***的原理和其防范措施
  7. Android中获取当前位置的使用步骤
  8. 程序员的800字作文
  9. haproxy 参数说明
  10. 多线程总结之旅(12):跨线程调用控件的几种方式