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. Beta 冲刺day3

    1.昨天的困难,今天解决的进度,以及明天要做的事情 昨天的困难:昨天主要是对第三方与企业复杂的逻辑关系进行分析和优化,以及进行部分模块的功能测试和代码测试. 今天解决的进度:根据前天得到的需求问题进行 ...

  2. Hive中Join的原理和机制

    转自:http://lxw1234.com/archives/2015/06/313.htm 笼统的说,Hive中的Join可分为Common Join(Reduce阶段完成join)和Map Joi ...

  3. [ 搭建Redis本地服务器实践系列一 ] :图解CentOS7安装Redis

    上一章 [ 搭建Redis本地服务器实践系列 ] :序言 作为开场白介绍了下为什么要写这个系列,从这个章节我们就开始真正的进入正题,开始搭建我们本地的Redis服务器.那么关于Redis的基本概念,什 ...

  4. java 保留字段volatile、transient、native、synchronized

    1.volatile Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程.当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享 ...

  5. CDN及CDN加速原理

    本想自己写这个主题的文章,但网上已经有人写了一篇非常好的文章,觉得难以望其项背.就没有必要再写,直接转载如下: 在不同地域的用户访问网站的响应速度存在差异,为了提高用户访问的响应速度.优化现有Inte ...

  6. Struts标签库详解【1】

    struts2标签详解 要在jsp中使用Struts2的标志,先要指明标志的引入.通过jsp的代码的顶部加入以下的代码: <%@taglib prefix="s" uri=& ...

  7. python发送手机动态验证码

    一.准备短信发送平台 首先进入http://user.ihuyi.com/nav/sms.html互亿天线,并且注册,进入首页 注册后会免费送50条消息 注册完后进入验证码通知短信,复制自己的api接 ...

  8. 【原】用Java编写第一个区块链(二)

    这篇文章将去介绍如何使用区块链进行交易. [本文禁止任何形式的全文粘贴式转载,本文来自 zacky31 的随笔] 目标: 在上一篇文章中,我们已经创建了一个可信任的区块链.但是目前所创建的链中包含的有 ...

  9. textarea去掉右下角拖拽

    /*去掉textarea右下角三角符号*/ resize : none;

  10. JAVA WEB项目中生成验证码及验证实例(附源码及目录结构)

    [我是一个初学者,自己总结和网上搜索资料,代码是自己敲了一遍,亲测有效,现将所有的目录结构和代码贴出来分享给像我一样的初学者] 作用 验证码为全自动区分计算机和人类的图灵测试的缩写,是一种区分用户是计 ...