async/await使用小tips

1,691 阅读3分钟

async/await是一种异步解决方案,相对于其他异步解决方案,async/await语法在使用上是比较简单的,使用起来跟同步方法没有太大差异。

使用async/await

function promiseFn () {
    return new Promise((resolve, reject) => {
        resolve(1);
    });
}

async function asyncFn() {
    const num = await promiseFn();
    console.log(num);  
}

asyncFn();  // 1

await 后面的内容,如果不是返回一个Promise,则会用Promise.resolve()进行一个隐式调用,确保返回的是一个Promise。

function notPromiseFn () {
    return 1;
}

async function asyncFn () {
    const num = await notPromiseFn();
    console.log(num);
}
async function asyncFn2 () {
    const num = await 666;
    console.log(num);   
}

asyncFn(); // 1

asyncFn2(); // 666

所以,其实我们可以不用管await后面返回的类型,都是可以使用async/await的。但如果不是异步函数的话,其实就没有必要这么用了,直接用同步的写法就好,毕竟async/await的目的就是用同步的模式来实现异步的操作的,同步代码也使用async/await就有点多此一举了。

异常处理

异常处理是平时编写代码中必须要考虑的问题,因此,在async/await中也必须要对异常情况进行处理。

function errorPromiseFn(type) {
    return new Promise((resolve, reject) => {
        if (type === 'error') {
            throw new Error('Error');
        }
        resolve(404);
    });
}

async function errorFn() {
    try {
        const res = await errorPromiseFn('error');
        console.log(res);
    } catch (err) {
        console.error(err);
    }
}

errorFn('error'); // 异常会被俘获

串行与并行

我们知道,同步代码都是串行执行的。但有的时候,我们并不希望都是串行执行的。比如,在需要请求多个没有相互依赖的接口数据时,最佳解决方案是并行执行。

function getData1() {
    return new Promise((resolve, reject) => {
        fetch(url).then(res => resolve(res));
    });
}

function getData2(url) {
    return new Promise((resolve, reject) => {
        fetch(url).then(res => resolve(res));
    });
}

async serialGetAllData() {
    // 创建promise并等待处理结果
    const data1 = await getData1();
    // 等待前面的处理结果完成,再创建promise并处理结果
    const data2 = await getData2();
    return {data1, data2};
}

serialGetAllData();

上面的serialGetAllData就行串行的先去请求data1再去请求data2,但是data2其实并不需要等到data1请求完成后再去执行。因此,我们希望他们能够同步的进行。

Promise.all实现异步并行

学过Promise的应该知道,Promise.all是支持多个Promise并行请求的。那么,在async/await中,我们就可以借助Promise.all来实现并行请求了。

async parallelGetAllData() {
    const [data1, data2] = await Promise.all([
        getData1(),
        getData2()
    ]);
    return {data1, data2};
}

parallelGetAllData();

先创建Promise再使用await

除了Promise.all方法外,还有另外一种方法实现并行操作:先创建Promise再使用await。

async parallelGetAllData() {
    // 创建多个promise实例
    const promise1 = getData1();
    const promise2 = getData2();
    // 同时等待多个promise的结果,
    // 假如promise1耗时三秒,promise2耗时两秒,
    // 由于promise1和promise2同时进行请求,
    // 因此只需3秒就可以得到data1和data2了
    const data1 = await promise1;
    const data2 = await promise2;
    return {data1, data2};
}

循环体中使用async/await

有时候,我们需要在循环体中去进行异步操作

async function serialLoop() {
    let promises = [getData1, getData2];
    for (let promise of promises) {
       const data = await promise();
       console.log(data);
    }
}

serialLoop();

很显然,上面的代码是串行执行的,如果getData1需要3秒,getData2需要2秒,那么整个过程就需要5秒才能执行完成。

在上一节中,我们知道了async/await可以改造为并行执行

async function parallelLoop() {
    let promises = [getData1(), getData2()];
    for (let promise of promises) {
        const data = await promise;
        console.log(data);
    }
}
parallelLoop();

这样,就只需要3秒就可以执行完了。