← 返回首页
Javascript基础教程(四十七)
发表时间:2021-08-02 00:19:19
async/await

1.async

带async关键字的函数,是声明异步函数,返回值是promise对象,如果async关键字函数返回的不是promise,会自动用Promise.resolve()包装。

例如:

    async function fn(){
        return "hello";
    }

    let foo = fn();
    console.log(foo);

运行结果:

Promise {<fulfilled>: "hello"}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "hello"

等同于:

    function fn(){
        return new Promise((resolve => {
            resolve("hello");
        }))
    }

   let foo = fn();
   console.log(foo);

2.await await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。

//语法
[return_value] = await expression;   //注意,返回并不是一个Promise对象,而是结果

遇到await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,继续执行await后面的代码。

例如:

    async function fn(){
        setTimeout(() => console.log("delay task running... "), 2000);
        return "success";
    }
    async function test() {
        let foo = await fn("success");  //返回的是结果
        console.log(foo);
    }
    test();
    console.log("ending now....");

运行结果:

ending now....
success
delay task running... 

如果上例改写如下:

    async function fn(){
        setTimeout(() => console.log("delay task running... "), 2000);
        return "success";
    }
    async function test() {
        let foo = fn("success");  //返回的是Promise对象;
        console.log(foo);
    }
    test();
    console.log("ending now....");

运行结果:

Promise {<fulfilled>: "success"}__proto__: Promise[[PromiseState]]: "fulfilled"[[PromiseResult]]: "success"
ending now....
delay task running... 

async最大的好处是解决了 then 多层回调。

假设:假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。我们仍然用 setTimeout 来模拟异步操作:

     /**
     * 传入参数 n,表示这个函数执行的时间(毫秒)
     * 执行的结果是 n + 200,这个值将用于下一步骤
     */
    async function takeLongTime(n) {
        return new Promise(resolve => {
            setTimeout(() => resolve(n + 200), n);
        });
    }

    function step1(n) {
        console.log(`step1 with ${n}`);
        return takeLongTime(n);
    }

    function step2(n) {
        console.log(`step2 with ${n}`);
        return takeLongTime(n);
    }

    function step3(n) {
        console.log(`step3 with ${n}`);
        return takeLongTime(n);
    }
    //Promise方案
    function doIt() {
        console.time("doIt");
        const time1 = 300;
        step1(time1)
            .then(time2 => step2(time2))
            .then(time3 => step3(time3))
            .then(result => {
                console.log(`result is ${result}`);
                console.timeEnd("doIt");
            });
    }

    doIt();

运行结果:

step1 with 300
step2 with 500
step3 with 700
result is 900
doIt: 1503.097900390625 ms

async 改写如下:

    /**
     * 传入参数 n,表示这个函数执行的时间(毫秒)
     * 执行的结果是 n + 200,这个值将用于下一步骤
     */
    async function takeLongTime(n) {
        return new Promise(resolve => {
            setTimeout(() => resolve(n + 200), n);
        });
    }

    function step1(n) {
        console.log(`step1 with ${n}`);
        return takeLongTime(n);
    }

    function step2(n) {
        console.log(`step2 with ${n}`);
        return takeLongTime(n);
    }

    function step3(n) {
        console.log(`step3 with ${n}`);
        return takeLongTime(n);
    }

     //async 写法
    //对比 promise写法,
   async function doIt() {
        console.time("doIt");
        const time1 = 300;
        const time2 = await step1(time1);
        const time3 = await step2(time2);
        const result = await step3(time3);
        console.log(`result is ${result}`);
        console.timeEnd("doIt");
    }

   doIt();

运行效果相同。我们发现 async 函数完美的解决了then的多重调用问题。流程清晰,直观、语义明显。