接着上一篇Generator co的使用 https://juejin.im/post/5ab51336f265da239d493ff4
这里继续说说js异步处理的方法 async await( 即Generator的语法糖)

async 是“异步”的简写,async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成,await 只能出现在 async 函数中

同样用上一篇中读取文件的例子,这里改写为

let bluebird = require('bluebird');
let fs = require('fs');
let read = bluebird.promisify(fs.readFile);
//await 命令后面的 Promise 对象,运行结果可能是 //rejected,所以最好把 await 命令放在 try...catch 代码块中。async function r(){try{let content1 = await read('1.txt','utf8');let content2 = await read(content1,'utf8');return content2;}catch(e){ console.log('err',e)}
}r().then(function(data){console.log('data',data);
},function(err){console.log('err1',err);
})

async await和generator的写法很像,就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成await

但async 函数对 Generator 函数做了改进:

1、内置执行器:Generator函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器.也就是说,async 函数的执行,与普通函数一模一样。

2、更好的语义:async 和 await,比起星号和 yield,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。

3、更广的适用性: co 函数库约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)

async 函数是非常新的语法功能,新到都不属于 ES6,而是属于 ES7。目前,它仍处于提案阶段,但是转码器 Babel 和 regenerator 都已经支持,转码后就能使用。

async 的作用

async 函数负责返回一个 Promise 对象
如果在async函数中 return 一个直接量,async 会把这个直接量通过Promise.resolve() 封装成 Promise 对象;
如果 async 函数没有返回值,它会返回 Promise.resolve(undefined)

await 在等待什么

一般我们都用await去等带一个async函数完成,不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值,所以,await后面实际可以接收普通函数调用或者直接量

如果await等到的不是一个promise对象,那跟着的表达式的运算结果就是它等到的东西;
如果是一个promise对象,await会阻塞后面的代码,等promise对象resolve,得到resolve的值作为await表达式的运算结果
虽然await阻塞了,但await在async中,async不会阻塞,它内部所有的阻塞都被封装在一个promise对象中异步执行

Async Await使用场景

如上面的例子,当需要用到promise链式调用的时候,就体现出Async Await的优势;

假设一个业务需要分步完成,每个步骤都是异步的,而且依赖上一步的执行结果,甚至依赖之前每一步的结果,就可以使用Async Await来完成

function takeLongTime(n) {return new Promise(resolve => {setTimeout(() => resolve(n   200), n);});
}
function step1(n) {console.log(`step1 with ${n}`);return takeLongTime(n);
}
function step2(m, n) {console.log(`step2 with ${m} and ${n}`);return takeLongTime(m   n);
}
function step3(k, m, n) {console.log(`step3 with ${k}, ${m} and ${n}`);return takeLongTime(k   m   n);
}async function doIt() {console.time("doIt");const time1 = 300;const time2 = await step1(time1);const time3 = await step2(time1, time2);const result = await step3(time1, time2, time3);console.log(`result is ${result}`);console.timeEnd("doIt");
}doIt();

如果用promise来实现

function doIt() {console.time("doIt");const time1 = 300;step1(time1).then(time2 => {return step2(time1, time2).then(time3 => [time1, time2, time3]);}).then(times => {const [time1, time2, time3] = times;return step3(time1, time2, time3);}).then(result => {console.log(`result is ${result}`);console.timeEnd("doIt");});
}doIt();

可见用promise,参数传递非常麻烦

下面的例子,指定多少毫秒后输出一个值。

function timeout(ms) {return new Promise((resolve) => {setTimeout(resolve, ms);});
}async function asyncPrint(value, ms) {await timeout(ms);console.log(value)
}asyncPrint('hello world', 50);

注意

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

await read('1.txt','utf8').catch(function(err){console.log(err);
})

await 只能出现在 async 函数中,如果用在普通函数,就会报错

async function dbFuc(db) {let docs = [{}, {}, {}];// 报错docs.forEach(function (doc) {await db.post(doc);});
}

上面代码会报错,因为 await 用在普通函数之中了。但是,如果将 forEach 方法的参数改成 async 函数,也有问题

async function dbFuc(db) {let docs = [{}, {}, {}];// 可能得到错误结果docs.forEach(async function (doc) {await db.post(doc);});
}

上面代码可能不会正常工作,原因是这时三个 db.post 操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用 for 循环。

async function dbFuc(db) {let docs = [{}, {}, {}];for (let doc of docs) {await db.post(doc);}
}

如果确实希望多个请求并发执行,可以使用 Promise.all 方法。

async function dbFuc(db) {let docs = [{}, {}, {}];let promises = docs.map((doc) => db.post(doc));let results = await Promise.all(promises);console.log(results);
}// 或者使用下面的写法async function dbFuc(db) {let docs = [{}, {}, {}];let promises = docs.map((doc) => db.post(doc));let results = [];for (let promise of promises) {results.push(await promise);}console.log(results);
}

总结

使用 async / await, 搭配 promise, 可以通过编写形似同步的代码来处理异步流程, 提高代码的简洁性和可读性。

Async Await 的优点: 1、解决了回调地狱的问题
2、支持并发执行
3、可以添加返回值 return xxx;
4、可以在代码中添加try/catch捕获错误

参考资料
1、https://segmentfault.com/a/1190000007535316

2、http://www.ruanyifeng.com/blog/2015/05/async.html

更多专业前端知识,请上 【猿2048】www.mk2048.com

Async Await相关推荐

  1. setTimeout、setInterval、promise、async/await的顺序详解(多种情况,非常详细~)

    本文很长,列举的情况很多. 在阅读本文之前,如果您有充足的时间,请新建一个项目与本文一同实践. 每段代码都有对应的解释,但是自己动手尝试印象才会更深哦~ setInterval:表示多久执行一次,需要 ...

  2. C# async await 学习笔记2

    C# async await 学习笔记1(http://www.cnblogs.com/siso/p/3691059.html) 提到了ThreadId是一样的,突然想到在WinForm中,非UI线程 ...

  3. promise 和 async await区别

     什么是Async/Await? async/await是写异步代码的新方式,以前的方法有回调函数和Promise. async/await是基于Promise实现的,它不能用于普通的回调函数. as ...

  4. angular2 学习笔记 ( Rxjs, Promise, Async/Await 的区别 )

    Promise 是 ES 6 Async/Await 是 ES 7 Rxjs 是一个 js 库 在使用 angular 时,你会经常看见这 3 个东西. 它们都和异步编程有关,有些情况下你会觉得用它们 ...

  5. async await:比requests 更强大

    最近公司 Python 后端项目进行重构,整个后端逻辑基本都变更为采用"异步"协程的方式实现.看着满屏幕经过 async await(协程在 Python 中的实现)修饰的代码,我 ...

  6. @async 默认线程池_.NET Web应用中为什么要使用async/await异步编程?

    布莱恩特:.NET Core开发精选文章目录,持续更新,欢迎投稿!​zhuanlan.zhihu.com 前言 1.什么是async/await? await和async是.NET Framework ...

  7. Atitit. Async await 优缺点 异步编程的原理and实现 java c# php

    Atitit. Async await 优缺点 异步编程的原理and实现 java c# php 1. async & await的来源1 2. 异步编程history1 2.1. 线程池 2 ...

  8. 8张图让你一步步看清 async/await 和 promise 的执行顺序

    2019独角兽企业重金招聘Python工程师标准>>> **摘要:**面试必问 原文:8张图帮你一步步看清 async/await 和 promise 的执行顺序 作者:ziwei3 ...

  9. 用 async/await 来处理异步

    引用出处:https://www.cnblogs.com/SamWeb/p/8417940.html 昨天看了一篇vue的教程,作者用async/ await来发送异步请求,从服务端获取数据,代码很简 ...

  10. 关于C#中async/await中的异常处理(上)

    关于C#中async/await中的异常处理(上) 参考文章: (1)关于C#中async/await中的异常处理(上) (2)https://www.cnblogs.com/sunjie9606/p ...

最新文章

  1. 【java】java获取对象属性类型、属性名称、属性值
  2. 微信小程序——收起和查看更多功能
  3. 基于javaSwing+文本存储的学生信息管理系统设计实现
  4. 计算机网络class1(概念、组成、功能和分类)
  5. word2016取消首字母大写 带图详细讲解
  6. oracle数据库考试答题,Oracle数据库试题
  7. ipad+mysql+客户端_MySQL QueryDB Client
  8. python 菜鸟联盟-菜鸟联盟python
  9. Linux wine系列——Ubuntu20.04安装wine教程 [2021.3]
  10. datav(datav)
  11. php调用pdf虚拟打印机,window_在Win7系统中怎么安装PDF彩色虚拟打印机?,前面说过,Word不能直接将文档 - phpStudy...
  12. 视频学习前端的经验之谈
  13. JAVA求数组最大值最小值总和均值
  14. 树莓派的一生:树莓派十年
  15. 邻接矩阵——无向图的实现
  16. python安装以后怎么打开_安装python后如何打开
  17. html5闪光效果,css特效-一道闪光在图片上划过
  18. 《秋波媚·七月十六日晚登高兴亭望长安南山》 陆游
  19. 最简单的推送提醒服务-Bark
  20. EAUML日拱一卒-微信小程序实战:位置闹铃 (5)-显示所在位置的信息

热门文章

  1. 机器学习中的算法-支持向量机(SVM)基础
  2. php网站 qq登陆,php写的插件网站接入QQ登录,QQ互联
  3. [http]HTTP状态码含义
  4. execl中设置的格式无法实现
  5. 2018/11/29 一个64位操作系统的设计与实现 03 (在Bochs上运行Boot程序)
  6. [NOI2012]美食节
  7. 一个线程加一运算,一个线程做减一运算,多个线程同时交替运行--synchronized...
  8. 数学图形之SineSurface与粽子曲面
  9. hibernate 映射四多对一双向映射
  10. linux下挂载iso镜像的方法