ES8的async/await是解决利用异步结构组织代码的问题,只有两个关键字async和await
async函数是什么
一句话,async函数是generator函数的语法糖;是generator加了内置执行器的结果,返回一个 Promise对象,可以用then来获取结果,进行下一步的操作
基本用法
async函数返回一个Promise对象,可以试用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等待异步操作完成,再接着执行函数体后面的语句
使用async关键字可以让函数具有异步特征,但总体上其代码仍然是同步求值的
语法
返回Promise对象
async函数返回一个Promise对象,其内部如果使用了return语句返回了值(如果没有return则返回undefined),则这个值会被Promise.resolve()包装成一个期约对象,成为then方法回调函数的参数
async函数内部抛出错误,会导致返回的Promise对象状态变成reject。抛出的错误对象会被catch方法回调函数接收到
Promise对象的状态变化
async函数返回的Promise对象的状态改变有两种情况:
- 内部所有await命令后面的Promise对象执行完毕
- 提前遇到return语句或者抛出错误
- 只有async函数内部异步操作执行完毕,才会执行then回调函数
await命令
因为异步函数主要针对不会马上完成的任务,所以自然需要一种暂停和恢复执行的能力。使用await关键字可以暂停异步函数代码的执行,等待期约解决
正常情况下,await命令后面是一个Promise对象,返回该对象的结果,如果不是Promise对象,就直接返回对应的值
await命令后面Promise对象如果变成reject,则reject参数会被catch回调函数接收到
任何一个await语句后面的Promise对象状态变为reject,整个async都会中断执行
错误处理
如果await后面的异步操作出错,等同于async函数返回的Promise对象被reject
防止出错的方法,就是将await放到try...catch代码块中
实现多次重复尝试
利用try...catch结构加async/await实现一个重试多次的函数,如果await操作成功就会推出循环,如果失败就会被catch捕捉,进行下一次循环
const superagent = require("superagent");
const NUM_RETRIES = 3;
async function test() {
let i;
for (i = 0; i < NUM_RETRIES; ++i) {
try {
await superagent("/bar.txt");
break;
} catch (error) {}
}
console.log(i);
}
test();
使用注意点
- await命令后面语句执行结果可能是reject,所以最好放到try...catch代码块中
- 多个await语句如果不存在继发关系,最好使用Promise.all让它们同时触发
- await命令只能用在async函数中
- async函数可以保留运行堆栈
async函数的实现原理
就是将Generator函数和自动执行器,包装在一个函数里