1、初识 async 函数
 
ES6中提供了两个很好的解决异步操作的方案 Promise 和 Generator,ES2017标准中引入的 async 函数就是建立在 Promise 和 Generator的基础之上,它是 Generator函数的语法糖,使异步操作更加方便
 
先通过一个异步读取文件的小栗子来对比下Promise、Generator 和 async 的异同点
const fs = require('fs')

function readFile(fileName) {
return new Promise((resolve, reject) => {
fs.readFile(fileName, (err, data) => {
if(err) {
reject(err)
}
resolve(data.toString())
})
})
}
(1)、通过 Promise 读取文件
readFile('data/a.txt').then(res => console.log(res))
.catch(err => console.log(err)) readFile('data/b.txt').then(res => console.log(res))
.catch(err => console.log(err)) readFile('data/c.txt').then(res => console.log(res))
.catch(err => console.log(err))
(2)、通过 Generator 函数读取文件
与 Promise 相比较,优点:把所有的接口都封装在一个函数里面了,缺点:代码量稍微多一点点
function* gen() {
yield readFile('data/a.txt')
yield readFile('data/b.txt')
yield readFile('data/c.txt')
} let it = gen() it.next().value.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
}) it.next().value.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
}) it.next().value.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
 
(3)、通过 async 函数读取文件
充分吸取了 Promise 和 Generator的优点,同时避免了它们的缺点
async function read() {
let readA = await readFile('data/a.txt')
let readB = await readFile('data/b.txt')
let readC = await readFile('data/c.txt') console.log(readA)
console.log(readB)
console.log(readC)
} read()

最终的输出结果

通过上例可以看出,async 函数就是将 Generator函数的星号("*")替换成了 async,把 yield 替换成了 await
 
async 函数对 Generator函数的改进,主要体现在三个方面:
 
(1)、内置执行器
async函数的执行,与普通函数一模一样,只需一行;而 Generator函数,需要调用next 方法
 
(2)、返回值是 Promise
async函数的返回值是Promise,这比 Generator函数返回一个 Iterator对象方便多了
 
(3)、更好的语义化
从字面意思上来讲,async是英文单词 asynchronous 的缩写,表示异步的;await中的 wait 是等待的意思。
 
因此相比 Generator函数中的星号和yield,语义更加清楚,async 表示这是一个异步操作的函数,await 表示紧跟在后面的表达式需要等待结果
 
 
2、async 函数的多种使用形式
// 函数声明
async function foo() {
// ....
} // 函数表达式
let foo = async function() {
// ....
} // 箭头函数
let foo = async() => {} // 对象的方法
let obj = {
name: 'Roger',
async foo() { }
}
obj.foo().then(res => {
// ....
}) // 类的方法
class Student{
constructor(name, age) {
this.name = name
this.age = age
}
async say() {
return `My name is ${this.name}, I'm ${this.age} years old !`
}
} let jim = new Student('Jim Green', 13)
jim.say().then(res => console.log(res)) // My name is Jim Green, I'm 13 years old !
3、基本用法
 
async 函数返回一个 Promise 实例对象,可以使用 then 方法添加回调函数。
 
当函数执行时,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句
 
// 休眠 ms 毫秒
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
})
} async function print(ms) {
console.log('start... ...')
await sleep(ms)
console.log('end... ...')
} print(1000)

(1)、async 函数内部 return语句返回的值,会成为then方法回调函数的参数
async function foo() {
return 'hello world'
} foo().then(res => console.log(res)) // hello world
(2)、async 函数内部抛出错误,会导致返回的 Promise对象变成reject状态,抛出的错误会被catch方法回调函数接收到
async function bar() {
return new Error('Error... ...')
} bar().then(res => console.log(res))
.catch(err => console.log(err)) // Error: Error... ...
(3)、只有 async 函数内部的异步操作执行完,才会执行 then方法指定的回调函数
async function baz() {
await new Promise(resolve => {
console.log('执行第一个异步操作')
setTimeout(resolve, 2000)
}) await new Promise(resolve => {
console.log('执行第二个异步操作')
setTimeout(resolve, 3000)
}) return '异步执行完毕再执行then方法'
} baz().then(res => {console.log(res)})

4、await 命令
 
await 用于等待一个 Promise对象,它只能在一个 async函数中使用
[return_value] = await expression

表达式:一个 Promise对象或者任何要等待的值

返回值:返回 Promise对象的处理结果。如果等待的不是 Promise对象,则返回该值本身
await命令会暂停当前 async函数的执行,等待 Promise处理完成。如果 Promise正常处理,其回调的 resolve函数参数会作为 await表达式的返回值,继续执行 async函数。如果 Promise处理异常,await表达式会把 Promise的异常原因抛出
 
// 如果 await 命令后的表达式的值不是一个 Promise,则返回该值本身
async function foo() {
return await 123
} foo().then(res => console.log(res)) // // 如果 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的返回值
async function bar() {
let f = await new Promise((resolve, reject) => {
resolve('我是表达式的返回值')
})
console.log(f) // 我是表达式的返回值 return 'ending'
} bar().then(res => {console.log(res)}) // ending // 如果 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出
async function baz() {
await new Promise((resolve, reject) => {
reject(new Error('出错啦......'))
})
} baz().then(res => console.log(res))
.catch(err => console.log(err)) // Error: 出错啦......
(1)、任何一个 await语句后面的 Promise对象变为 reject状态,那么整个 async函数都会中断执行
 
async function foo() {
await Promise.reject('error')
return 'ending' // 未执行
} foo().then(res => console.log(res))
// Uncaught (in promise) error
(2)、如果希望当前面的异步操作失败时,不要中断后面的异步操作,可以把前面的 await放在try...catch结构里面
 
async function foo() {
try{
await Promise.reject('error')
} catch(e) { }
return await Promise.resolve('执行完毕')
} foo().then(res => console.log(res)) // 执行完毕
还可以在 await后面的 Promise对象再跟一个 catch方法,处理前面可能出现的错误
 
async function foo() {
await Promise.reject('error').catch(err => console.log(err))
return '执行完毕'
} foo().then(res => console.log(res)) // 执行完毕
(3)、如果想让多个异步操作同时触发,缩短程序的执行时间,可以参考如下两种写法
 
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]); // 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

JS异步操作新体验之 async函数的更多相关文章

  1. ES6的新特性(18)——async 函数

    async 函数 含义 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 Generato ...

  2. async 函数-----------------解决异步操作隧道的亮光

    之前也学过,只是没有学好,公司现在用的都是async函数 , 所以决定把它弄懂.最近看了看阮一峰的博客,做下记录. 异步I/O不就是读取一个文件吗,干嘛要搞得这么复杂?异步编程的最高境界,就是根本不用 ...

  3. js异步回调Async/Await与Promise区别 新学习使用Async/Await

    Promise,我们了解到promise是ES6为解决异步回调而生,避免出现这种回调地狱,那么为何又需要Async/Await呢?你是不是和我一样对Async/Await感兴趣以及想知道如何使用,下面 ...

  4. node js 异步运行流程控制模块Async介绍

    1.Async介绍 sync是一个流程控制工具包.提供了直接而强大的异步功能.基于Javascript为Node.js设计,同一时候也能够直接在浏览器中使用. Async提供了大约20个函数,包含经常 ...

  5. 初识async函数

    为什么会出现async函数 首先从大的方面来说,出现async函数时为了解决JS编程中的异步操作,再往具体说就是为了对以往异步编程方法的一种改进,也有人说仅仅只是Generator 函数的语法糖,这个 ...

  6. 深入浅出ES6教程『async函数』

    大家好,本人名叫苏日俪格,大家叫我 (格格) 就好,在上一章节中我们学到了Symbol & generator的用法,下面我们一起来继续学习async函数: async [ə'zɪŋk]:这个 ...

  7. 前端知识点回顾之重点篇——ES6的async函数和module

    async函数 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是 Generator 函数的语法糖 什么是语法糖? 意指那些没有给计算机语言添加新功能,而只是 ...

  8. es6学习笔记-async函数

    1 前情摘要 前段时间时间进行项目开发,需求安排不是很合理,导致一直高强度的加班工作,这一个月不是常说的996,简直是936,还好熬过来了.在此期间不是刚学会了es6的promise,在项目有用到pr ...

  9. 17.async 函数

    async 函数 async 函数 含义 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 ...

随机推荐

  1. Elasticsearch JavaApi

    官网JavaApi地址:https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-search.html 博 ...

  2. 安装JDK,配置环境变量

    计算机(右键)-属性-高级系统设置-环境变量1.新建系统变量 : JAVA_HOMEC:\Program Files (x86)\Java\jdk1.6.0_10(你的JDK安装路径)2.在系统变量p ...

  3. nfs 、ftp 和samba都有什么区别?

    NFS:Network File System 是已故的Sun公司制定的用于分布式访问的文件系统,它的本质是文件系统.主要在Unix系列操作系统上使用,基于TCP/IP协议层,可以将远程的计算机磁盘挂 ...

  4. linux监控系统的状态

    1.命令w的第一行和uptime或者用upload2.system load averages 表示单位时间短内活动的进程数3.查看cpu的个数和核数processor.physical id 4.v ...

  5. 你可能不知道的 JavaScript 中数字取整

    网上方法很多,标题党一下,勿拍 ^_^!实际开发过程中经常遇到数字取整问题,所以这篇文章收集了一些方法,以备查询. 常用的直接取整方法 直接取整就是舍去小数部分. 1.parseInt() parse ...

  6. 节流throttle和防抖debounce

    underscore.js提供了很多很有用的函数,今天想说说其中的两个.这两个函数都用于限制函数的执行. debounce 在解释这个函数前,我们先从一个例子看下这个函数的使用场景.假设我们网站有个搜 ...

  7. Scrapy爬虫框架第五讲(linux环境)【download middleware用法】

    DOWNLOAD MIDDLEWRE用法详解 通过上面的Scrapy工作架构我们对其功能进行下总结: (1).在Scheduler调度出队列时的Request送给downloader下载前对其进行修改 ...

  8. Scrapy 1.4 文档 01 初窥 Scrapy

    初窥 Scrapy Scrapy 是用于抓取网站并提取结构化数据的应用程序框架,其应用非常广泛,如数据挖掘,信息处理或历史存档. 尽管 Scrapy 最初设计用于网络数据采集(web scraping ...

  9. dva/docs/GettingStarted.md

    进入目录安装依赖: npm i 或者 yarn install开发: npm run dev npm install 太慢,试试yarn吧.建议用npm install yarn -g进行安装. Co ...

  10. Sublime Text 3 Build 3065 License key 注册码 秘钥

    -– BEGIN LICENSE -– Andrew Weber Single User License EA7E-855605 813A03DD 5E4AD9E6 6C0EEB94 BC99798F ...