async函数
async函数就是Generator函数的语法糖。
以下是使用Generator函数和async函数来读取文件的方式
const fs = require('fs');
const readFile = function(filename){
return new Promise(function(resolve,reject){
fs.readFile(filename,function(err,data){
if (err) return reject(err);
resolve(data);
})
})
}
const gen = function* (){
let x = yield readFile('Afile');
let y = yield readFile('Bfile');
console.log(x.toString());
console.log(y.toString());
}
const g = gen();
g.next();
// 使用async函数的写法
const asyncReadFile = async function(){
let x = await readFile('Afile');
let y = await readFile('Bfile');
console.log(x.toString());
console.log(y.toString());
}
asyncReadFile();
async函数的优化体现在以下方面
-
内置执行器
async函数内部自带执行器,不需要再编写函数执行器,而Generator函数自动执行需要执行器或者是co模块. 因此,调用async函数只需要在函数名后面加上()即可。
-
语义化更加的清晰
await和async比*和yield语义更加的清晰。
-
使用更加灵活
co模块规定,yield后面的表达式必须是Thunk函数或者是Promise对象。而async函数的await后面表达式不限定类型, 可以是Thunk函数,Promise对象,也可以是基本数据类型。
-
返回值是Promise对象
async函数的返回值是Promise对象,可以直接使用then方法进行操作,而Generator函数执行的返回值是Iterator对象, 需要使用next()方法进行操作。
async语法
- async函数返回的是Promise对象
- async内部的return语句返回的值,会成为then方法回调函数的参数。
async function f(){
return 'async';
}
f().then(v=>{console.log(v)}); // async
- async函数内部抛出的错误,会造成返回的Promise状态变成reject;抛出的错误也会被catch方法所捕获。
async function fn(){
return new Error('出错了');
}
fn().then(()=>{console.log(1)}).catch(e=>{console.log(e)}); // 出错了
- Promise对象的状态变化 async函数返回的Promise对象的状态,必须要等到该函数内部所有的await命令后面的Promise对象执行完,才会发生状态的改变, 除非是遇到错误或者是return语句,否则当await后面的Promise对象没有执行完成之前,async内部的所有的Promise的状态就都是pending状态。
- await命令 一般情况,await命令后面是一个Promise对象,如果不是的话,就会被立即转成一个resolve状态的Promise状态。
async function fn(){
return await 123;
}
fn().then(v=>{console.log(v)}) // 123
await后面的Promise转台如果变成reject的话,那么会被catch的回调方法所捕获到。
async function fn(){
return new Error('报错了');
}
fn().then(v=>{console.log(v)}).catch(e=>{console.log(e)}); // 报错了
- 只要一个await语句后面的Promise变成reject,那么整个async就都会被中断。整个async函数返回的Promise状态就变成了reject。
- 处理某个await后面的Promise出错的方法 如果不确定某个await后面的Promise是否会出错的话,将其放入到try…catch中。
使用注意点⚠️
- 尽可能的将可能会出错的await后面的Promise写在try…catch语句中
- 如果多个await之间不存在相互的依赖关系,那么可以让他们同时触发调用
let foo = await getFoo();
let bar = await getBar();
// 以上两个await后面的Promise没有关联,可以采用如下的方式,将其同时调用
let [foo,bar] = await Promise.all([getFoo(),getBar()]);
- await只能用在async函数中,如果用于普通的函数的话,就会报错。
异步Generator函数
异步Generator函数就是async函数和Generator函数的结合。
async function* fn(){
yield 'hello world';
}
const genObj = fn();
fn.next().value.then(v=>console.log(v));
yield* 语句
yield* 也可以跟上一个异步遍历器
async function* gen1(){
yield 'a';
yield 'b';
return 2;
}
async function* gen2(){
const results = yield* gen1() // results:2
}