async函数
基本概念
async
函数是什么?一句话,它就是 Generator 函数的语法糖。
将上一章的代码改成 async 函数的版本:
const { promisify } = require("util");
const path = require('path')
const file1 = path.join(__dirname, './text/1.txt')
const file2 = path.join(__dirname, './text/2.txt')
const readFileP = promisify(readFile)
function* f() {
let data1 = yield readFileP(file1)
console.log('耶,完成了1,数据是' + data1);
let data2 = yield readFileP(file2)
console.log('耶,完成了2,数据是' + data2);
}
//async函数的版本
async function f() {
let data1 = await readFileP(file1)
console.log('耶,完成了1,数据是' + data1);
let data2 = await readFileP(file2)
console.log('耶,完成了2,数据是' + data2);
}
比较后就会发现,async
函数的版本就是将 Generator 函数的星号(*
)替换成async
,将yield
替换成await
。
定义async函数
使用async关键字定义一个async函数:
async function f() {
let data1 = await readFileP(file1)
console.log('耶,完成了1,数据是' + data1);
let data2 = await readFileP(file2)
console.log('耶,完成了2,数据是' + data2);
}
执行async函数
执行async
函数则相当于执行了一个自动运行的Generator函数,async
函数如果返回的结果不是Promise,则会运行结果包装成一个Promise返回:
async function f() {
console.log(1);
}
f().then(()=>{
console.log(2);
})
async function f() {
console.log(1);
return 'done'
}
f().then(value => {
console.log(value);
})
await关键字
与yield
类似,async
函数中可以使用await
关键字,await
关键字后面一般会写一个Promise实例,async
函数执行的过程中,每次遇到await
关键字,会将控制权转回外部环境。
- 如果
await
后面是Promise实例,则会等到该 Promise实例被resolve后,才会把本次await
到下次await
之间的代码推到MircoTask(微任务)
中等待执行,并且await
的返回值是该Promise实例resolve的值 - 如果
await
后面不是Promise实例,则会立即将本次await
到下次await
之间的代码推到MircoTask(微任务)
中等待执行,并且await
的返回值是等于await
后面表达式的值:
async function f() {
let data = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('a')
}, 2000)
})
console.log(data);
}
//f()
//console.log('end')
如果await
后面不是Promise 实例
async function f() {
let data = await 'a'
console.log(data);
}
f()
console.log('end');
//end
//a
async函数的错误处理
如果Promise被reject或抛出错误,await之后的代码不会执行,因此,需要使用try..catch
对await
进行错误捕捉:
async function f() {
try {
let data = await new Promise((resolve, reject) => {
setTimeout(() => {
reject('123')
}, 2000)
})
//后续代码无法执行
console.log('done');
}catch (e) {
console.log('发生错误:',e);
}
}
f()
async函数处理并发异步任务
如果,async
函数中的每个await
都是等到前面await
resolve后才会执行,如果想并发执行,可以使用Promise.all
:
/*并发处理异步*/
async function f() {
let time1 = new Date()
let [data1,data2] = await Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('123')
}, 2000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('123')
}, 3000)
})
])
console.log(data1,data2,'用时:'+ (new Date() - time1));
}
f()
async函数与Promise的对比
用async
函数写异步逻辑相比Promise会更加简洁,在处理不同异步结果相互依赖,错误处理,if...else分支等情况时更加简便:
const {readFile} = require('fs')
const { promisify } = require("util");
const path = require('path')
const file1 = path.join(__dirname, './text/1.txt')
const file2 = path.join(__dirname, './text/2.txt')
const file3 = path.join(__dirname, './text/3.txt')
const readFileP = promisify(readFile)
function f1() {
readFileP(file1).then(data1 =>{
console.log('耶,完成了1,数据是' + data1);
return readFileP(file2)
}).then(data2 => {
console.log('耶,完成了1,数据是' + data2);
return readFileP(file3)
}).then(data3 => {
console.log('耶,完成了1,数据是' + data3);
})
}
async function f2() {
let data1 = await readFileP(file1)
console.log('耶,完成了1,数据是' + data1);
let data2 = await readFileP(file2)
console.log('耶,完成了2,数据是' + data1 + data2);
let data3 = await readFileP(file3)
console.log('耶,完成了2,数据是' + data1 + data2 + data3);
}
f()