es6快速入门 系列 - async
其他章节请看:
async
前文我们已经知道 promise 是一种异步编程的选择。而 async 是一种用于执行异步任务更简单的语法。
Tip:建议学完 Promise 在看本文。
async 函数
async 函数是使用 async 关键字声明的函数。就像这样:
async function fa(){
}
async 函数可以看作由多个异步操作包装成的一个 Promise 对象。
async 函数返回 Promise
async 函数总是返回一个 Promise 对象。如果一个 async 函数的返回值看起来不是 promise,那么它将会被隐式地包装在一个 promise 中。请看示例:
async function fa() {
return 1
}
// 等价于
function fa() {
return Promise.resolve(1)
}
console.log( fa() instanceof Promise) // true
即使 async 方法中没有显示的 return ,async 方法仍会返回 Promise。请看示例:
async function fa() {}
console.log( fa() instanceof Promise)
fa 方法等价于:
function fa() {
return Promise.resolve()
}
async 函数多种形式
async 函数有多种使用形式。例如:
// 函数表达式
const fa = async funciton() {};
// 对象的方法
let obj = {async foo(){}}
// Class 的方法
class Dog{
async say(){}
}
// 箭头函数
const fa = async () => {}
形式虽然很多,但都是在函数前面增加 async 关键字。
async 函数中的 return
async 函数内的 return 返回值,会成为 then() 方法回调函数的参数。请看示例:
async function foo() {
return 'hello'
}
foo().then(v => {
console.log(v)
})
// hello
async 函数内部抛出的错误会导致返回的 Promise 对象变为 reject 状态。抛出的错误对象会被 catch 方法回调接收到。请看示例:
async function foo() {
throw new Error('fail')
return 'hello'
}
foo().catch(v => {
console.log(v.message)
})
// fail
Promise 对象的状态变化
async 函数返回的 Promise 对象必须等到内部所有 await 命令后的 Promise 对象执行完才会发生状态变化,除非遇到 return 语句,或者抛出错误才会立刻结束。请看示例:
function createPromise(val, time = 1000){
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(val)
resolve(val)
}, time)
})
}
async function foo() {
let a = await createPromise(1)
let b = await createPromise(2)
return {a, b}
}
foo().then(v => {
console.log(v)
}, v => {
console.log(v.message)
})
/*
1
2
{ a: 1, b: 2 }
*/
这段代码需要 2 秒,等待内部两个 Promise 状态都置为已完成,才会输出 { a: 1, b: 2 }
。
如果遇到 return 或者抛出错误,则会立即结束。就像这样:
async function foo() {
// 遇到 return
return 1
// 或抛出错误
// throw new Error('fail')
let a = await createPromise(1)
let b = await createPromise(2)
return {a, b}
}
await
asyn 函数可能包含 0 个或多个 await 表达式。就像这样:
async function fa() {
return await 1
}
await 表达式会暂停整个 async 函数的执行进程并出让其控制权,只有当其等待的基于 promise 的异步操作被兑现或被拒绝之后才会恢复进程。promise 的解决值会被当作该 await 表达式的返回值。
await 的返回值
首先看一段代码:
async function fa() {
const result = await 1
return result
}
fa().then(v => {
console.log(v)
})
// 1
为什么 result 是 1?
首先,因为 await 命令后面是一个 Promise 对象。如果不是,会被转为一个立即 resolve 的 Promise 对象。所以下面 fa() 方法是相等的:
async function fa() {
return await 1
}
// 等价于
async function fa() {
return await Promise.resolve(1)
}
而在 Promise 中所学,我们知道 fa() 方法又等于如下代码:
async function foo() {
return await new Promise((resolve, reject) => {
resolve(1)
})
}
其次,Promise 的解决值会被当作该 await 表达式的返回值。所以 result 等于 1。
如果删除 fa() 方法中的 return,将输出 undefined。请看示例:
async function fa() {
// 删除 return
await 1
}
fa().then(v => {
console.log(v)
})
// undefined
reject 中断 async 函数
await 命令后的 Promise 对象如果变成 reject 状态,则 reject 的参数会被 catch 方法回调函数接收。就像这样:
async function foo() {
await Promise.reject(1) // {1}
}
foo().then(v => {
console.log(v)
}).catch(v => {
console.log(`catch, ${v}`)
})
// catch, 1
请注意,await 语句(行{1})前面没有 return 语句,但是 reject() 方法的参数依然传入了 catch 方法的回调函数中,这点与 resolve 状态不相同。
只要一个 await 语句后面的 Promise 变成 reject,那么整个 async 函数都会中断。请看示例:
async function foo() {
await Promise.reject(1)
await new Promise((resolve, reject) => {
console.log(2)
resolve()
})
return 3
}
foo().then(v => {
console.log(v)
}).catch(v => {
console.log(`catch, ${v}`)
})
// catch, 1
由于第一个 await 后面的 Promise 变成 reject,整个 async 函数就中断执行。
如果我们希望前一个异步操作失败,也不中断后面的异步操作,可以这么写:
try{
await Promise.reject(1)
}catch(e){
}
// 亦或者
// 在 Promise 一文中提到拒绝处理程序能恢复整条链的执行
await Promise.reject(1).catch(() => {})
...
如果 await 后面的异步操作出错,那么等同于 async 函数返回的 Promise 对象被 reject。就像这样:
async function foo() {
await new Promise((resolve, reject) => {
throw new Error('fail')
})
return 3
}
foo().then(v => {
console.log(v)
}).catch(v => {
console.log(`catch, ${v}`)
})
// catch, Error: fail
防止出错的方法也是将其放在 try ... catch 方法中。下面例子使用 try...catch 实现多次尝试:
function request(v){
return new Promise((resolve, reject) => {
if(v == 2){
console.log(`resolve${v}`)
resolve(v)
}else{
console.log(`fail${v}`)
throw new Error('fail')
}
})
}
async function foo() {
for(let i = 0; i < 5; i++){
try{
await request(i)
break
}catch(e){} // {1}
}
return 'end'
}
foo().then(v => {
console.log(v)
}).catch(v => {
console.log(`catch, ${v}`)
})
// fail0 fail1 resolve2 end
这段代码,如果 await 操作成功,则会使用 break 语句退出循环;如果失败,则会被 catch(行{1}) 捕获,然后进入下一轮循环。
await 与并行
下面的代码,会依次输出 1 和 2,属于串行。
function createPromise(val, time = 1000){
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(val)
resolve(val)
}, time)
})
}
async function foo() {
let a = await createPromise(1)
let b = await createPromise(2)
}
foo()
// 1 2
如果多个异步操作不存在继发关系,最好让它们同时触发。将 foo() 方法改为下面任一方式:
// 方式一
async function foo() {
let p1 = createPromise(1)
let p2 = createPromise(2)
// 至此,两个异步操作都已经发出
await p1
await p2
}
// 方式二
async function foo() {
let [p1, p2] = await Promise.all([createPromise(1), createPromise(2)])
}
再次运行,只需要 1 秒就会同时输出 1 2。
async 函数中的 await
await 关键字只能用在 async 函数中。请看示例:
async function fa(){
let arr = [1, 2, 3]
arr.forEach(v => {
await v
})
}
// SyntaxError: await is only valid in async function
这段代码将报语法错误。
如果将 forEach 方法的参数改为 async 函数,就像这样:
function createPromise(val, time = 1000){
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(val)
resolve(val)
}, time)
})
}
async function fa(){
let arr = [1, 2, 3]
// 改为 async 函数
arr.forEach(async v => {
await createPromise(v)
})
}
fa()
// 1 2 3
等待 1 秒后同时输出 1 2 3。因为这 3 个异步操作是并发执行。
如果希望多个请求并发执行,也可以使用 Promise.all 方法。就像这样:
// 替换 fa() 方法即可
async function fa(){
let arr = [1, 2, 3]
let promises = arr.map(v => createPromise(v))
let results = await Promise.all(promises)
console.log(results)
}
而如果需要继发,可以采用 for 循环:
// 替换 fa() 方法即可
async function fa(){
let arr = [1, 2, 3]
// 将 forEach 改为 for 循环
for(let i = 0; i < arr.length; i++){
await createPromise(arr[i])
}
}
每过一秒,会依次输出 1 2 3。
其他章节请看:
es6快速入门 系列 - async的更多相关文章
- es6 快速入门 系列 —— 变量声明:let和const
其他章节请看: es6 快速入门 系列 变量声明:let和const 试图解决的问题 经典的 var 声明让人迷惑 function demo1(v){ if(v){ var color='red' ...
- es6 快速入门 系列 —— promise
其他章节请看: es6 快速入门 系列 Promise Promise 是一种异步编程的选择 初步认识Promise 用 Promise 来实现这样一个功能:发送一个 ajax,返回后输出 json ...
- es6 快速入门 系列 —— 类 (class)
其他章节请看: es6 快速入门 系列 类 类(class)是 javascript 新特性的一个重要组成部分,这一特性提供了一种更简洁的语法和更好的功能,可以让你通过一个安全.一致的方式来自定义对象 ...
- es6 快速入门 系列 —— 对象
其他章节请看: es6 快速入门 系列 对象 试图解决的问题 写法繁杂 属性初始值需要重复写 function createPeople(name, age){ // name 和 age 都写了 2 ...
- es6 快速入门 系列
es6 快速入门(未完结,持续更新中...) 前言 为什么要学习es6 es6对于所有javaScript开发者来说,非常重要 未来,es6将构成javaScript应用程序的基础 es6中很多特性, ...
- es6 快速入门 —— 函数
其他章节请看: es6 快速入门 系列 函数 函数是所有编程语言的重要组成部分,es6之前函数语法一直没什么变化,遗留了许多问题,javaScript开发者多年来不断抱怨,es6终于决定大力度更新函数 ...
- webpack 快速入门 系列 —— 性能
其他章节请看: webpack 快速入门 系列 性能 本篇主要介绍 webpack 中的一些常用性能,包括热模块替换.source map.oneOf.缓存.tree shaking.代码分割.懒加载 ...
- 快速入门系列--WebAPI--01基础
ASP.NET MVC和WebAPI已经是.NET Web部分的主流,刚开始时两个公用同一个管道,之后为了更加的轻量化(WebAPI是对WCF Restful的轻量化),WebAPI使用了新的管道,因 ...
- python 全栈开发,Day88(csrf_exempt,ES6 快速入门,Vue)
BBS项目内容回顾 1. 登陆页面 1. 验证码 1. PIL(Pillow) 2. io 2. ORM 1. 增删改查 3. AJAX $.ajax({ url: '', type: '', dat ...
随机推荐
- 三分钟了解B2B CRM系统的特点
最近很多朋友想了解什么是B2B CRM系统,说到这里小Z先来给大家说说什么是B2B--B2B原本写作B to B,是Business-to-Business的缩写.正常来说就是企业与企业之间的生意往来 ...
- Scanner, BufferedReader, InputStreamReader 与ACM模式输入
Scanner, BufferedReader, InputStreamReader 与ACM模式输入html { -webkit-print-color-adjust: exact } * { bo ...
- [Linux] Linux命令行与Shell脚本编程大全 Part.2
进程 Linux是多用户系统,多个用户可以在不同地方通过网络连接到一个Linux系统上进行操作 w:显示登录人员信息 date:显示当前日期.时间和时区 up:从开机登录到现在经过的时间 load a ...
- ActiveMQ FileServer漏洞(详细)
半个月前,巡检时发现服务器出现不明进程,对其进行了处理,由于当时没有做详细记录,在这里把大致过程描述一下. 症状: ps命令发现出现几个不明进程, 1.于/tmp下运行的,名称随机的进程.占用CPU高 ...
- Linux如何查看文件的创建、修改时间?
Linux如何查看文件的创建.修改时间? 利用stat指令查看文件信息 三种时间的介绍 ATime --文件的最近访问时间 只要读取时间,ATime就会更新 MTime --文件的内容最近修改的时间 ...
- bond0 配置ip不生效排查方法
今天巡检的时候,发现无法连接到服务器上面了,于是到机房连接到显示器查看: 1.先检查网卡,协议有没有问题. 2.远程链接的网卡名称是bond0,用ifconfig看看网卡配置,然后发现配置的 ...
- Linux进阶之给nginx设置登录用户验证
一.nginx开启访问验证 使用nginx搭建的站点,如果不想让所有人都能正常访问,那么可以设置访问认证,只有用户输入正确的用户名和密码才能正常访问. 在nginx下,提供了ngx_http_auth ...
- 11.4 iftop:动态显示网络接口流量信息
iftop是一款实时流量监控工具,可用于监控TCP/IP连接等,必须以root用户的身份运行. 一般最小化安装系统都是没有这个命令的,需要使用yum命令额外安装,而且还要从epel源下载. ift ...
- centos7 启动docker失败
现象:Centos7.3通过yum安装完docker后,启动docker失败 机器的系统版本:CentOS Linux release 7.3.1611 (Core) centos7,执行完安装命令: ...
- mysql开启远程访问和oracl用户锁定问题
开启mysql远程访问 Grant all privileges on *.* to 'root'@'%' identified by 'root'; Flush privileges; oracl锁 ...