# ES7 前端异步玩法:async/await 理解

在最新的 ES7(ES2017)中提出的前端异步特性:async、await。

# 什么是 async、await?

async 顾名思义是 “异步” 的意思,async 用于声明一个函数是异步的。而 await 从字面意思上是 “等待” 的意思,就是用于等待异步完成。并且 await 只能在 async 函数中使用

通常 async、await 都是跟随 Promise 一起使用的。为什么这么说呢?因为 async 返回的都是一个 Promise 对象同时 async 适用于任何类型的函数上。这样 await 得到的就是一个 Promise 对象 (如果不是 Promise 对象的话那 async 返回的是什么 就是什么);

await 得到 Promise 对象之后就等待 Promise 接下来的 resolve 或者 reject。

来看一段简单的代码:

async function testSync() {
     const response = await new Promise(resolve => {
         setTimeout(() => {
             resolve("async await test...");
          }, 1000);
     });
     console.log(response);
}
testSync();//async await test...

就这样一个简单的 async、await 异步就完成了。使用 async、await 完成异步操作代码可读与写法上更像是同步的,也更容易让人理解。

# async、await 串行并行处理

串行:等待前面一个 await 执行后接着执行下一个 await,以此类推

async function asyncAwaitFn(str) {
    return await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(str)
        }, 1000);
    })
}
const serialFn = async () => { // 串行执行
    console.time('serialFn')
    console.log(await asyncAwaitFn('string 1'));
    console.log(await asyncAwaitFn('string 2'));
    console.timeEnd('serialFn')
}
serialFn();

可以看到两个 await 串行执行的总耗时为两千多毫秒。

并行:将多个 promise 直接发起请求(先执行 async 所在函数),然后再进行 await 操作。

async function asyncAwaitFn(str) {
    return await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(str)
        }, 1000);
    })
}
const parallel = async () => { // 并行执行
    console.time('parallel')
    const parallelOne = asyncAwaitFn('string 1');
    const parallelTwo = asyncAwaitFn('string 2')
    // 直接打印
    console.log(await parallelOne)
    console.log(await parallelTwo)
    console.timeEnd('parallel')
}
parallel()

通过打印我们可以看到相对于串行执行,效率提升了一倍。在并行请求中先执行 async 的异步操作再 await 它的结果,把多个串行请求改为并行可以将代码执行得更快,效率更高。

# async、await 错误处理

JavaScript 异步请求肯定会有请求失败的情况,上面也说到了 async 返回的是一个 Promise 对象。既然是返回一个 Promise 对象的话那处理当异步请求发生错误的时候我们就要处理 reject 的状态了。

在 Promise 中当请求 reject 的时候我们可以使用 catch。为了保持代码的健壮性使用 async、await 的时候我们使用 try catch 来处理错误。

async function catchErr() {
      try {
          const errRes = await new Promise((resolve, reject) => {
                setTimeout(() => {
                    reject("http error...");
                 }, 1000);
           );
                // 平常我们也可以在 await 请求成功后通过判断当前 status 是不是 200 来判断请求是否成功
                // console.log(errRes.status, errRes.statusText);
        } catch(err) {
             console.log(err);
        }
}
catchErr(); //http error...

以上就是 async、await 使用 try catch 处理错误的方式。

虽然 async、await 也使用到了 Promise 但是却减少了 Promise 的 then 处理使得整个异步请求代码清爽了许多。