ECMAScript - async-await 初步

此篇是上篇Promise的续

引例:顺序读取并输出3个文件

// 读取函数
const fs = require('fs');
function readFile(path) {
    return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
            if(err) {
                return reject(err);
            }
            resolve(data.toString());
        })
    })
}

// async await
async function readFileFor3() {
    console.log(await readFile("./1"));
    console.log(await readFile("./2"));
    console.log(await readFile("./3"));
}

特点:

1. await语句只能放在async函数中

否则会出错。

2. await后面紧跟着一个Promise对象,只有当这个Promise对象的状态变成fulfiled(以下fulfiled等同于resolved)时,才会执行后面的代码

文中以下Promise对象执行“完成”,均表示Promise状态变成了fulfiled,变成rejected的情况在后面讨论。

3. await后面的Promise对象将返回它resolve()的值;

因此可以直接用变量赋值接收。

4. async函数执行,返回一个Promise对象,仅当函数中所有的await后面的Promise都执行完,才会改变状态,此时可用then()进行回调处理;

即所有的Promise都fulfiled。

5. await后面的Promise对象如果变更为rejected状态,则整个async函数都会终止执行,除非对该错误进行处理

如果不进行错误处理,则整个async函数会终止执行,async函数返回的Promise也不可以用then方法处理,因此错误处理显得很重要,方法也比较多,只简单记录

对单个await进行错误处理

await后面紧跟着的是一个Promise对象,因此对其进行.catch()即可,这种方法不影响后面代码的执行

async function readFileFor3() {
    console.log(await readFile("./1").catch((err) => {console.log(err)}));
    console.log(await readFile("./21").catch((err) => {console.log(err)}));
    console.log(await readFile("./3").catch((err) => {console.log(err)}));
}

对async函数返回的Promise进行错误处理

readFile("./3").catch((err) => {console.log(err)});

即使这样可以捕捉到错误,依然要记得,此时产生错误的await后面的代码并没有执行。

继发和并发

每一个await是独立的异步操作,只有当上一个await完成,才会执行下一个await,例如

async function waitForAll() {
    await waitTime(3000); // 每个waitTime(3000)会花费3s的时间
    await waitTime(3000);
    await waitTime(3000);
    // 等待 9s
    console.log("all over");
}

如果需要多个await同时开始执行,可以利用 Promise.all([promise1, promise2...]),比如

async function waitForAll() {
    await Promise.all([waitTime(3000), waitTime(3000), waitTime(3000)]);
    // 3s 即可完成
    console.log("all over");
}

Promise.all()

Promise.all()方法将多个 Promise 实例,包装成一个新的 Promise 实例。
接收一个数组作为参数,数组元素均为Promise实例,返回新的Promise实例,设为p

  1. 只有所有元素的状态都变成fulfilled,p的状态才会变成fulfilled,此时元素的返回值组成一个数组,传递给p的回调函数;
  2. 只要其中有一个被rejected,p的状态就变成rejected,此时第一个rejected的实例的返回值,会传递给p的回调函数

应用:封装定时器的增强函数

function TimerWrapper(fn) {
    return async () => {
        let time = 0;
        const timeout = setInterval(() => {
            console.log(++time)
        }, 1000);
        // await 执行函数
        await fn();
        // 最后清除定时器
        clearInterval(timeout);
    }
}

这个函数可以传入一个函数,返回的函数执行时会进行计时,从而很好的说明执行顺序和时间的问题。

async function readFileRaw() {
    await Promise.all([waitTime(3000), waitTime(3000), waitTime(3000)]);
    console.log("all over");
}

TimerWrapper(readFileRaw1)() 
/*
 * 输出: 1,2,allover
 *
*/

附录: 晚秋


posted @ 2021-01-23 17:22  紫苏薄荷  阅读(54)  评论(0编辑  收藏  举报

> To be continued