参考资料:理解javaScript中的async/await,感谢原文作者的总结,本文在理解的基础上做了一点小小的修改,主要为了加深自己的知识点掌握

学完了Promise,我们知道可以用then链来解决多层回调问题,但是这还不是最理想的操作,我们需要调用很多个then链才能达到要求,那么有没有一种更简便代码量更少的方式达到then链相同的结果呢?asynv和await就很好地解决了这个问题,首先用async声明一个异步函数,然后再用await等待异步结果,把以前then链的结果放到直接放在await,非常方便。

那么,async和await原理是什么呢?为什么可以用这样的语法来优化then链呢?

1. async/await是什么?

async/await其实是Promise的语法糖,它能实现的效果都能用then链来实现,这也和我们之前提到的一样,它是为优化then链而开发出来的。从字面上来看,async是“异步”的简写,await译为等待,所以我们很好理解async声明function是异步的,await等待某个操作完成。当然语法上强制规定await只能出现在asnyc函数中,我们先来看看async函数返回了什么:

  1. async function testAsy(){
  2. return 'hello world';
  3. }
  4. let result = testAsy();
  5. console.log(result)

这个async声明的异步函数把return后面直接量通过Promise.resolve()返回Promise对象,所以如果这个最外层没有用await调用的话,是可以用原来then链的方式来调用的:

  1. async function testAsy(){
  2. return 'hello world'
  3. }
  4. let result = testAsy()
  5. console.log(result)
  6. result.then(v=>{
  7. console.log(v) //hello world
  8. })

联想一下Promise特点——异步无等待,所以当没有await语句执行async函数,它就会立即执行,返回一个Promise对象,非阻塞,与普通的Promise对象函数一致。

重点就在await,它等待什么呢?

按照语法说明,await等待的是一个Promise对象,或者是其他值(也就是说可以等待任何值),如果等待的是Promise对象,则返回Promise的处理结果;如果是其他值,则返回该值本身。并且await会暂停当前async function的执行,等待Promise的处理完成。若Promise正常处理(fulfillded),其将回调的resolve函数参数作为await表达式的值,继续执行async function;若Promise处理异常(rejected),await表达式会把Promise异常原因抛出;另外如果await操作符后面的表达式不是一个Promise对象,则返回该值本身。

2. 深入理解async/await

我们来详细说明一下async/await的作用。await操作符后面可以是任意值,当是Promise对象的时候,会暂停async function执行。也就是说,必须得等待await后面的Promise处理完成才能继续:

  1. function testAsy(x){
  2. return new Promise(resolve=>{setTimeout(() => {
  3. resolve(x);
  4. }, 3000)
  5. }
  6. )
  7. }
  8. async function testAwt(){
  9. let result = await testAsy('hello world');
  10. console.log(result); // 3秒钟之后出现hello world
  11. }
  12. testAwt();

await 表达式的运算结果取决于它等的东西。

如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。

如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。

我们再把上面的代码修改一下,好好体会“阻塞”这个词

  1. function testAsy(x){
  2. return new Promise(resolve=>{setTimeout(() => {
  3. resolve(x);
  4. }, 3000)
  5. }
  6. )
  7. }
  8. async function testAwt(){
  9. let result = await testAsy('hello world');
  10. console.log(result); // 3秒钟之后出现hello world
  11. console.log('tangj') // 3秒钟之后出现tangj
  12. }
  13. testAwt();
  14. console.log('tangSir') //立即输出tangSir

这就是 await 必须用在 async 函数中的原因。async 函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个 Promise 对象中异步执行。await暂停当前async的执行,所以'tangSir''最先输出,hello world'和‘tangj’是3秒钟后同时出现的。

3. async和await简单应用

上面已经说明了 async 会将其后的函数(函数表达式或 Lambda)的返回值封装成一个 Promise 对象,而 await 会等待这个 Promise 完成,并将其 resolve 的结果返回出来。

现在举例,用 setTimeout模拟耗时的异步操作,先来看看不用 async/await 会怎么写

  1. function takeLongTime() {
  2. return new Promise(resolve => {
  3. setTimeout(() => resolve("long_time_value"), 1000);
  4. });
  5. }
  6.  
  7. takeLongTime().then(v => {
  8. console.log("got", v); //一秒钟后输出got long_time_value
  9. });

如果改用 async/await 呢,会是这样

  1. function takeLongTime() {
  2. return new Promise(resolve => {
  3. setTimeout(() => resolve("long_time_value"), 1000);
  4. });
  5. }
  6.  
  7. async function test() {
  8. const v = await takeLongTime();
  9. console.log(v); // 一秒钟后输出long_time_value
  10. }
  11.  
  12. test();

tankLongTime()本身就是返回的 Promise 对象,所以加不加 async结果都一样。

4. 处理then链

前面我们说了,async和await是处理then链的语法糖,现在我们来看看具体是怎么实现的:

假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。我们仍然用setTimeout来模拟异步操作:

  1. /**
  2. * 传入参数 n,表示这个函数执行的时间(毫秒)
  3. * 执行的结果是 n + 200,这个值将用于下一步骤
  4. */
  5. function takeLongTime(n) {
  6. return new Promise(resolve => {
  7. setTimeout(() => resolve(n + 200), n);
  8. });
  9. }
  10.  
  11. function step1(n) {
  12. console.log(`step1 with ${n}`);
  13. return takeLongTime(n);
  14. }
  15.  
  16. function step2(n) {
  17. console.log(`step2 with ${n}`);
  18. return takeLongTime(n);
  19. }
  20.  
  21. function step3(n) {
  22. console.log(`step3 with ${n}`);
  23. return takeLongTime(n);
  24. }

现在用 Promise 方式来实现这三个步骤的处理。

  1. function doIt(){
  2. console.time('doIt');
  3. let time1 = 300;
  4. step1(time1)
  5. .then((time2) => step2(time2))
  6. .then((time3) => step3(time3))  
  7. .then((result) => {
  8. console.log(`result is ${result}`);
  9. console.timeEnd("doIt");
  10. })
  11. }
  12.  
  13. doIt();
  14.  
  15. //执行结果为:
  16. //step1 with 300
  17. //step2 with 500
  18. //step3 with 700
  19. //result is 900
  20. //doIt: 1510.2490234375ms

输出结果 result 是 step3() 的参数 700 + 200 = 900doIt() 顺序执行了三个步骤,一共用了 300 + 500 + 700 = 1500 毫秒,和 console.time()/console.timeEnd() 计算的结果一致。

如果用 async/await 来实现呢,会是这样:

  1. async function doIt() {
  2. console.time('doIt');
  3. let time1 = 300;
  4. let time2 = await step1(time1);//将Promise对象resolve(n+200)的值赋给time2
  5. let time3 = await step1(time2);
  6. let result = await step1(time3);
  7. console.log(`result is ${result}`);
  8. console.timeEnd('doIt');
  9. }
  10.  
  11. doIt();
  12.  
  13. //执行结果为:
  14. //step1 with 300
  15. //step2 with 500
  16. //step3 with 700
  17. //result is 900
  18. //doIt: 1512.904296875ms

显然我们用async/await简单多了。

5. Promise处理结果为rejected

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

  1. async function myFunction() {
  2. try {
  3. await somethingThatReturnAPromise();
  4. } catch (err){
  5. console.log(err);
  6. }
  7. }
  8.  
  9. //另一种写法
  10. async function myFunction() {
  11. await somethingThatReturnAPromise().catch(function(err) {
  12. console.log(err);
  13. })
  14. }

【学习笔记】深入理解async/await的更多相关文章

  1. C#线程学习笔记九:async & await入门二

    一.异步方法返回类型 只能返回3种类型(void.Task和Task<T>). 1.1.void返回类型:调用方法执行异步方法,但又不需要做进一步的交互. class Program { ...

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

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

  3. C#线程学习笔记十:async & await入门三

    一.Task.Yield Task.Yield简单来说就是创建时就已经完成的Task,或者说执行时间为0的Task,或者说是空任务,也就是在创建时就将Task的IsCompeted值设置为0. 我们知 ...

  4. C#线程学习笔记八:async & await入门一

    一.涉及内容 async & await是C# 5.0引入的,控制台输出所使用的$符号(拼接字符串)是C# 6.0引入的,其功能类似于string.Format()方法. 二.多线程.异步.同 ...

  5. Koa2学习(二)async/await

    Koa2学习(二)async/await koa2中用到了大量的async/await语法,要学习koa2框架,首先要好好理解async/await语法. async/await顾名思义是一个异步等待 ...

  6. 微信小程序开发:学习笔记[7]——理解小程序的宿主环境

    微信小程序开发:学习笔记[7]——理解小程序的宿主环境 渲染层与逻辑层 小程序的运行环境分成渲染层和逻辑层. 程序构造器

  7. 理解 async/await 的执行

    这是一篇简单的短文章,方便理解. 开局先丢官宣:sec-async-function-definitions 这个链接是对 await 的解释,解释了它的执行. await 的执行意味着(官宣巴拉巴拉 ...

  8. 理解async/await

    async 和 await 在干什么 任意一个名称都是有意义的,先从字面意思来理解.async 是“异步”的简写,而 await 可以认为是 async wait 的简写.所以应该很好理解 async ...

  9. Java_JVM学习笔记(深入理解Java虚拟机)___重点

    http://chenzhou123520.iteye.com/category/196061 转载 JVM学习笔记(一):运行时数据区 JVM学习笔记(二):JVM中对象访问的两种方式 JVM学习笔 ...

随机推荐

  1. leveldb 学习记录(七) SSTable构造

    使用TableBuilder构造一个Table struct TableBuilder::Rep { // TableBuilder内部使用的结构,记录当前的一些状态等 Options options ...

  2. UVA 10534 Wavio Sequence

    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=17&p ...

  3. Android 软件管理工具类Utils

    Android 软件管理工具类Utils /** * Created by uilubo on 2015/9/30. * 工具类 */ public class Utils { public stat ...

  4. Win7 VS2015编译wxWidgets-3.1.0

    下载 https://www.wxwidgets.org/downloads/ 打开SLN工程 D:\CPPLibs\wxWidgets-3.1.0\build\msw\wx_vc14.sln 编译 ...

  5. MFC:Tab控件嵌入对话框

    1.先建立一个对话框MFC应用程序,然后在工具箱里面把Tab Control控件放到对话框中的合适位置上. 再在对话框类中,声明一个CTabCtrl变量: CTabCtrl m_tab; 变量m_ta ...

  6. SWPU-ACM集训队周赛之组队赛(3-11) C题题解

    点这里去看题 模拟,注意细节 #include<stdio.h> #include<string.h> int main() { ]; //q[]储存正负信息 scanf(&q ...

  7. day11_雷神_udp、多进程等

    day11 1.网络编程 1.1 udp协议 client端 import json import socket server_addr = ('127.0.0.1',9090) sk = socke ...

  8. 项目中使用同一dll的不同版本

    在一个项目中,因为使用了一些插件,这些插件使用了不同版本的log4net,有1.2版本,有2.0版本的.当运行的时候发生冲突. 解决办法:在config中加入如下的配置 <dependentAs ...

  9. ReactNative学习笔记(三)打包、调试、运行等相关介绍

    各种命令 个人习惯在项目根目录下把一些常见命令写成bat文件,以后每次要执行什么只需要双击即可: 编译.生成.运行并启动packager(debug模式): react-native run-andr ...

  10. SSH框架搭建过程详解

    Spring.Struts2.Hibernate框架: 具体三大框架的知识以前的文章写过,在这里整合 Spring框架知识:http://www.cnblogs.com/xuyiqing/catego ...