ES6+学习系列 – Async/Await

Async 是ES7 酝酿时加入的一个特性,利用原生特性支持的异步功能。

用法

非常简单,举个栗子:

const processor = () => {
    //模拟返回一个延时对象,3秒后返回处理结果
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(true);
        }, 1000);
    });
};

const asyncFun = async () => {
    console.log('start');
    const result = await processor();
    console.log('end');
};

asyncFun();

结果当然是输出“start”后,等待1秒,再输出“end”。

以上,
asyncFun 可以通过 AsyncFunction 函数声明, AsyncFunction 表达式, Async 方法, 以及 Async箭头函数创建的。
await 一元表达式,适用于AsyncFunction的函数体中。在函数声明或表达式的形参中使用,会导致语法错误。

获取返回值

const processor = () => {
    //模拟返回一个延时对象,3秒后返回处理结果
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('200');
        }, 1000);
    });
};

const asyncFun = async () => {
    const result = await processor();
    console.log(result);
};

Await的主要功能,是处理异步上下文,ES8中说明了,Await兼容Promise,这也是为什么promise通过resolve处理的返回值可以被await表达式接收。
await的处理过程包含了对promise返回值的处理,进而向async对象返回一个状态,被称作 resumptionValue。虽然这个值不会被获取,但await会接收该返回状态,使得程序继续运行。通常这样的操作被称为抽象运算。

对比

说起异步处理,Promise是最早被支持的新的异步特性,相对于传统回调的层次嵌套,Promise已经简洁了不少。

const f = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(123);
    }, 2000);
  });
};

const testAsync = () => {
  f().then((t) => {
    console.log(t);
  });
};

testAsync();

简单对比一下,await写法更简洁。

再举一个直观的例子:
假设有promise1、promise2、promise3 三个异步处理,现在想对promise1和promise2的结果进行处理,并且返回一个异步的处理结果promise3

const makeRequest = async () => {
    const value1 = await promise1()
    const value2 = await promise2(value1)
    return promise3(value1, value2)
}

早在promise时代,这样的逻辑往往被人诟病,当然也可以通过创建一个统一的流程去控制多个promise的结果,不过,在这里只有3个异步,如果是一个异步队列,await的写法将更为便利。

当然,不只是这一个优点。比如,异常处理:

const makeRequest = () => {
    try {
        // try/catch 1
        getJSON().then(result => {
            // JSON.parse可能会出错
            const data = JSON.parse(result)
            console.log(data);
        }).catch((err) => {
            // try/catch 2
            console.log(err)
        })
    } catch (err) {
        console.log(err)
    }
}

在promise中自带了try..catch的错误处理,当出错时,会将错误抛给reject函数,所以直接throw new Error,也会被Promise所捕获。
因此以上,try/catch 1是无法捕获JSON.parse中报错的。而错误被 try/catch 2代理。

对于普通的异步事件来说,比如有try中执行的setTimeout,在setTimeout回调中发生的错误,无法被try捕获,因为此时setTimeout这一句已经被执行,异步回调无法被监控。

而await会有更好的方式处理

const makeRequest = async () => {
    try {
        // JSON.parse可能会出错
        const data = JSON.parse(await getJSON())
        console.log(data)
    } catch (err) {
        console.log(err)
    }
}

支持情况

当前,只有浏览ES8的官方文档,才能找到AsyncFunction的相关内容,也就是说遵循ES8规范的浏览器,一定会支持这一特性。
从目前浏览器的支持情况来看,国内外主流浏览器(PC/Mobile)均已支持。
凸显了ES6之后JS功能渐进式的增强2333333.

学习参考
官方链接

发表评论

电子邮件地址不会被公开。 必填项已用*标注