ES6读书简记·async

CY 2019年01月11日 98次浏览

基本概述

ES2017 标准引入了 async 函数,它就是 Generator 函数的语法糖。

async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已

asyncGenerator相比:

  • 内置执行器,不需要调用next方法,不需要co模块

  • 更好的语义,async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

  • 更广的适用性,async函数的await命令后面,可以是 Promise 对象和原始类型的值

  • async函数的返回值是 Promise 对象,可以使用then方法添加回调函数

函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句

多种使用形式:

// 函数声明
async function foo() {}

// 函数表达式
const foo = async function () {};

// 对象的方法
let obj = { async foo() {} };

// Class 的方法
class Storage {
  // ...
  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

// 箭头函数
const foo = async () => {};

async函数内部return语句返回的值,会成为then方法回调函数的参数

async函数内部抛出错误,那么返回的Promise对象就会走catch()

只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数,除非遇到return或者有错误

await 命令

await命令后面如果不是 Promise 对象,就直接返回对应的值。

await命令后面是一个thenable对象等同于 Promise 对象。

await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法中的回调函数接收到

任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行

处理await后面的Promisereject,可以使用try...catch也可以使用catch()

使用注意点

  • 最好把await命令放在try...catch代码块中

  • 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

    这里如果不理解,只需要知道一句话即可,Promise新建后会立即执行,所以在使用await之前,Promise已经执行了。

    // 写法一
    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函数和自动执行器包装在同一个函数里。

async function fn(args) {
  // ...
}

// 等同于

function fn(args) {
  return spawn(function* () {
    // ...
  });
}

与其他异步处理方法的比较

Promise,会有一堆的thencatch,语义不容易看出来

Generator写法又缺少自动执行器。

async函数简洁,符合语义,又不需要用户自己写自动执行器。