Skip to content

简介

  • async/await 是基于 Promise 实现的,不能用于普通的回调函数
  • async/await 与 Promise 一样是非阻塞的
  • async/await 使得异步代码看起来像同步代码

基本用法

async 函数就是 Generator 函数的语法糖,它的改进如下:

  • 内置执行器,与普通函数一样。
  • 更语义,async 和 await ,比起星号和 yield。
  • 更广的适应性,async 函数的 await 命令后面,可以是 Promise 对象和原始类型的值
  • 返回值是 Promise,可以用 then 指定下一步操作

async 的使用形式

// 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)
// 箭头函数
const foo = async () => {};
// Class 的方法
class Storage {
    async getAvatar(name) {
        const cache = await this.cachePromise;
        return cache.match(`/avatars/${name}.jpg`);
    }
}

返回 Promise 对象

async 函数返回一个 Promise 对象,async 函数内部 return 语句的返回值会成为 then 方法回调函数的参数。 async 函数内部抛出错误会导致返回的 Promise 对象变为 reject 状态,错误对象会被 catch 方法接收到。

Promise 对象状态变化

async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完, 才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有 async 函数内部的异步操作执行完, 才会执行 then 方法指定的回调函数。

await 命令

await 命令后面是一个 Promise 对象。如果不是,会被转成一个立即 resolve 的 Promise 对象。 只要一个 await 语句后面的 Promise 变为 reject ,那么整个 async 函数都会中断执行。

错误处理

如果 await 后面的异步操作出错,那么等同于 async 函数返回的 Promise 对象被 reject 且后续操作会被中断

  • await 放在 try...catch 结构里面
  • await 后面的 Promise 对象再跟一个 catch 方法

使用注意点

  • 最好把 await 命令放在 try...catch 代码块中
  • 多个 await 命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
  • await 命令只能用在 async 函数之中,如果用在普通函数,就会报错

async 实现的原理

  • async 函数的实现原理就是将 Generator 函数和自动执行器,包装在一个函数里。
javascript
async function fn(args) {
  // ...
}
// 等同于(spawn函数就是自动执行器)
function fn(args) {
  return spawn(function* () {
    // ...
  });
}