async 关键字用于声明异步函数,await 用于在async函数中将异步代码变为同步,阻塞代码的执行

对于promise和generator不熟悉的朋友可以移步看看这些文章

Promise的理解与使用(一)
Promise的理解和使用(二)
手写promise之分步解析
javascript事件循环机制及面试题详解

async、await的推导

我们用案例推出async await 关键字的作用。
异步函数getRequestData,作用是等待2s将输入的函数返回。

function getRequestData(data) {return new Promise((resolve, reject) => {setTimeout(() => {resolve(data);}, 2000);});
}

连续调用函数3次,传入"aaa",并依次拼接 “bbb”, “ccc”,最后的结果为,等待6s输出 “aaabbbccc”。

回调地狱式实现
getRequestData("aaa").then((res) => {getRequestData(res + "bbb").then((res) => {getRequestData(res + "ccc").then((res) => {console.log("result", res);});});
});

回调地狱式代码可读性和可维护性都很差,为解决这一问题,我们尝试链式调用。

链式调用
getRequestData("aaa").then((res) => {return getRequestData(res + "bbb");}).then((res) => {return getRequestData(res + "ccc");}).then((res) => {console.log("res", res);});

通过链式调用使得代码可读性稍强了一些,但这样的代码还是不太好理解,再来对其进行优化

generator
function* showData() {const res1 = yield getRequestData("aaa");const res2 = yield getRequestData(res1 + "bbb");const res3 = yield getRequestData(res2 + "ccc");console.log("res", res3);
}const generator = showData();
generator.next().value.then(res=>{generator.next(res).value.then(res=>{generator.next(res).value.then(res=>{console.log(res)})})
})

通过yield来对函数传参与取值,generator函数中进行请求的代码就变得简单起来,但next调用似乎更加复杂了,仍然有函数嵌套的情况,不过调用next方法是有迹可循的,可以用递归来实现。

const generator = showData();
function execGenerator(generator){function exec(res){const gen = generator.next(res)if(gen.done){return gen.value}return gen.value.then(re=>{exec(re)})}exec()
}
execGenerator(generator)

封装next方法调用之后,异步请求就变得像同步代码一样,可以等待上一个函数执行成功再调用下一个函数,且使得代码可读性更强。

aysnc、await

最终async、await版代码如下所示,其实就是generator和promise的语法糖,省去了next方法递归的过程。

async function showData(){const res1 = await getRequestData("aaa");const res2 = await getRequestData(res1 + "bbb");const res3 = await getRequestData(res2 + "ccc");console.log("res", res3);
}
showData()

async函数与普通函数的区别

返回值

async函数也可以有返回值,它的返回值与promise一样分为三种类型

  • 返回值为基本数据类型,会被 Promise.resolve 包裹,执行成功的回调
  • 返回值为promise,执行的结果与该promise一致
  • 返回值为实现了thenable的对象,执行结果为then函数中的结果
async function foo() {// return 'hello'// return new Promise((resolve, reject)=>{//   reject('fail')// })return {then: (resolve, reject) => {reject("fail");},};
}const promise = foo();
promise.then((res) => {console.log("res:", res);}).catch((err) => {console.log("err:", err);});

thenable中返回reject,所以异步函数的结果也为reject,执行catch函数的逻辑

抛出异常

普通函数中抛出异常,会直接中断程序的执行,后面的代码都不会执行

function bar(){throw new Error('error')
}
bar()
console.log('上面代码抛出异常了')

而异步函数中抛出异常,只需要定义catch方法,是不会中断程序执行的

async function foo() {throw new Error('error')
}
const promise = foo();
promise.then((res) => {console.log("res:", res);}).catch((err) => {console.log("进入了catch方法");});
console.log('上面代码抛出异常了')

async其它注意点

异步函数执行reject

promise可能返回resolve或者reject,当执行reject时,async函数执行的时候需要定义catch方法

function getData() {return new Promise((resolve, reject) => {setTimeout(() => {reject("fail");}, 1000);});
}
async function foo() {const promise = await getData();console.log(promise);
}
foo()

当没有定义catch方法时,是会直接报错的

await执行结果

await后面会跟上一个表达式,表达式会返回promise,await会等待promise执行resolve时,才会继续往后执行。
await后的表达式也有三种情况,与async函数返回值类型一致

  • 表达式为基本数据类型,会被 Promise.resolve 包裹,会执行成功
  • 表达式为promise,执行的结果与该promise一致
  • 表达式为实现了thenable的对象,执行结果为then函数中的结果
async function foo() {await Promise.reject("promise执行了reject方法");console.log("await下面一行代码还会执行吗");
}
foo().catch((err) => {console.log("err", err);
});
console.log("全局的代码呢");

当await后的表达式执行失败时,后面的代码就不会执行了

async函数的执行顺序

await下面的代码需要等到await后的表达式执行完成才执行

async function bar() {console.log("2");return new Promise((resolve) => {resolve();});
}
async function foo() {console.log("1");await bar();console.log("3");
}
foo();
console.log("4");

await后的表达式其实会执行promise的方法,所以await下面的代码其实会放到微任务中

面试题

async function async1 () {console.log('async1 start')await async2();console.log('async1 end')
}async function async2 () {console.log('async2')
}console.log('script start')setTimeout(function () {console.log('setTimeout')
}, 0)async1();new Promise (function (resolve) {console.log('promise1')resolve();
}).then (function () {console.log('promise2')
})
console.log('script end')
  • 函数async1、async2被定义,但是没有调用,首先输出 “script start”
  • setTimeout 中的的内容会被放到宏任务队列中,最后执行
  • 调用函数async1,输出 “async1 start”,执行函数async2,输出 “async2”,函数 async2下方的输出"async1 end"将会被放到微任务队列中
  • 执行promise的executor部分,输出 “promise1”,then 方法里的输出"promise2"将被放到微任务队列中
  • 输出 “script end”
  • 执行微任务队列中的代码,依次输出 “async1 end”、“promise2”
  • 执行宏任务队列中的代码,输出 “setTimeout”

图示如下

执行结果如下

以上就是async、await的推导过程及用法,关于js高级,还有很多需要开发者掌握的地方,可以看看我写的其他博文,持续更新中~

async、await其实是generator和promise的语法糖相关推荐

  1. 事件循环机制 + ES7:Async/Await(基于generator原理实现)附详细示例分析

    文章目录 一.事件循环 任务队列 宏任务和微任务 循环机制 简单示例 二.Async/Await 1. async 2. await 3. 原理 4. 示例(红字分析为关键) 一.事件循环 任务队列 ...

  2. 有了async/await,你可以丢掉promise链了

    异步函数可能会一直存在,但有些人认为async/await可能会被抛弃. 为什么? 一个常见的误解是async/await和promise是完全不同的东西. 但其实async/await是基于prom ...

  3. Promise async/await的理解和用法

    Promise && async/await的理解和用法 为什么需要promise(承诺)这个东西 在之前我们处理异步函数都是用回调这个方法,回调嵌套的时候会发现 阅读性 和 调试 的 ...

  4. async/await原来这就是语法糖

    带大家基本了解了Promise内部的实现原理,而提到Promise,就不得不提一个东西,那就是async/await,async/await是一个很重要的语法糖,他的作用是用同步方式,执行异步操作.那 ...

  5. async function_理解 Iterator, Generator 和 Async/Await

    戳蓝字「前端技术优选」关注我们哦! 这里重点理解他们三者分别是什么,有什么区别,以及分别适用什么场景 Iterator Iterator是最简单最好理解的,在很久之前我写过一篇文章 循环的秘密 里面讨 ...

  6. es6 --- promise和async/await的区别

    首先需要了解async函数: async是Generator函数的语法糖: // 使用Generator依次读取两个文件 var fs = require('fs'); var readFile = ...

  7. js异步解决方案 --- 回调函数 vs promise vs generater/yield vs async/await

    javascript -- 深度解析异步解决方案 高级语言层出不穷, 然而唯 js 鹤立鸡群, 这要说道js的设计理念, js天生为异步而生, 正如布道者朴灵在 node深入浅出--(有兴趣的可以读一 ...

  8. JavaScript异步编程【下】 -- Generator、Async/await

    文章内容输出来源:拉勾教育 大前端高薪训练营 前言 在JavaScript异步编程[上]和 JavaScript异步编程[中]中,我们已经讲到了处理异步编程的两种方法:回调函数 和 Promise. ...

  9. promise 、async/await 的原理及实现

    前言 事件循环机制 由于 javascript 引擎是采用单线程运行机制,执行耗时过大的操作时会造成页面的阻塞,为了解决页面的阻塞问题,js 将任务分为 同步任务.异步任务,随之而来的是异步带来的执行 ...

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

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

最新文章

  1. vtuber面部捕捉工具_泰国程序员开发VTuber形象生成系统,人人都能当虚拟偶像
  2. java可以使用c语言中的输入,c语言中的scanf在java中应该怎么表达,Scanner类。
  3. spring boot 使用swagger
  4. 贪心---leetcode-376摆动序列
  5. Asp.Net Mvc表单提交之List集合
  6. CSP-S/J2019认证相关内容
  7. Ubuntu18.04安装微信(方式二)
  8. 正则表达式功能以及应用
  9. 2018 大数据学习入门必备规划
  10. ADS仿真 之 直流仿真示例
  11. Fdfs环境搭建及整合Java
  12. 项目管理第五章项目范围管理
  13. 【已解决】您的PHP似乎没有安装运行WordPress所必需的MySQL扩展
  14. CF235C Cyclical Quest
  15. Nuscenes数据集转换voc_xml格式用于yolov4训练
  16. C#开发 虚拟翻书软件
  17. 关于SimpleDateFormat处理时间格式容易忽视的问题
  18. oracle取同期和上期,取同期和上期数据
  19. 图论应用 floyd(弗洛伊德)算法、dijkstra(迪杰斯特拉)算法
  20. 死锁定理与资源分配图化简法

热门文章

  1. win10如何一键还原系统
  2. Facebook开发者创建APP生成KeyHash
  3. 1等于0.循环9吗?
  4. Javascript Module Pattern,公共属性不能获取到最新值(Javascript revealing module pattern, public properties)
  5. 沈阳移动打造“爱贝通”、“校讯通”业务助少年儿童健康成长
  6. BaaS、FaaS、Serverless都是什么馅儿?
  7. 产品思维训练 | 卖菜的店同时也卖水果,卖水果的店为什么不卖菜?
  8. 动态规划 -- 活动时间问题
  9. ROS2初学者教程(Dashing和Eloquent)Windows
  10. 简单好用又免费的百度翻译mac桌面端