iT邦幫忙

1

React 學習筆記_17(JavaScript 中的異步函數(async/await))

  • 分享至 

  • xImage
  •  

簡介

async 異步函數是 ECMAScript 第七版(ES7)才被支援的語法,而目前還沒被大部分的JavaScript Engine引入,如果需要使用需要使用babel之類的工具;而異步函數和一般的函數一樣,只不過可以在此函數內使用await的語法去執行並等待非同步工作(Promise),可以告別以往冗長的callback function。

async 和 await 是什麼?

sync 是“異步”的簡寫,而await 可以認為是async wait 的簡寫,注意!!await只能出現在async函數中。

async的return?

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

const result = testAsync();
console.log(result);

輸出 :
https://ithelp.ithome.com.tw/upload/images/20200407/20124767u3qbjblBKw.png

可以看到async函數return的是一個Promise Object,如果在async function中return一個直接的變數,async會通過Promise.resolve()將它封裝成Promise,若在沒有await的情況下執行async函數會"立即"執行返回一個Promise Object。

await ?

一般來說await是在等待一個async函數的完成,因為async函數return一個Promise Object,所以await可以用於等待一個async的return值。注意!!await不僅用於等Promise Object它也可以接普通函數或是直接的變數。

function getSomething() {
    return "something";
}

async function testAsync() {
    return Promise.resolve("hello async");
}

async function test() {
    const v1 = await getSomething();
    const v2 = await testAsync();
    console.log(v1, v2);
}

test();

由於await後面可以接普通的函數與直接變數,所以上面的程式是可以執行的。
結果:
https://ithelp.ithome.com.tw/upload/images/20200407/20124767iQi9FMx4I3.png

async/await實例

以setTimeout模擬好費時間的非同步操作,先看看過去的寫法:

function takeLongTime() {
    return new Promise(resolve => {
        setTimeout(() => resolve("long_time_value"), 1000);
    });
}

takeLongTime().then(v => {
    console.log("got", v);
});

使用async/await寫法 :

function takeLongTime() {
    return new Promise(resolve => {
        setTimeout(() => resolve("long_time_value"), 1000);
    });
}

async function test() {
    const v = await takeLongTime();
    console.log(v);
}

test();

這兩個程式都會在1秒後輸出"long_time_value",注意!!由於async是return一個Promise,而function takeLongTime也是return一個Promise所以功能與async function takeLongTime()...一樣。

async/await 的優勢

使用async/await 寫法的優勢在於處理多個then,使用過去的Promise通過then來解決多層callback function會相對複雜,而使用async/await可以達到一樣的效果並且比較直白,對於閱讀與維護變得更為簡單。

舉一個例子,有一個程式中分許多個步驟,而每一個步驟都是非同步的,並且將上一個步驟地結果傳給你下一個步驟當作輸入參數。

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");
    });
};

使用async/await寫法 :

    doIt = async() => {
        console.time("doIt");
        const time1 = 300;
        const time2 = await step1(time1);
        console.log("time2 = " + time2);
        const time3 = await step2(time2);
        console.log("time3 = " + time3);
        const result = await step3(time3);
        console.log(`result is ${result}`);
        console.timeEnd("doIt");
    };

    doIt();

結果 :
https://ithelp.ithome.com.tw/upload/images/20200407/201247676NWNVr9uXT.png
將time1傳遞給step1,經過300ms後會將非同步的結果(Promise.resolve)return給time2,而再將time2傳入step2,經過(300+200)ms後return給time3,最後將time3傳入step3中,經過(500+200)ms後return給result,所以總共耗時300 + 500 + 700 = 1500ms,使用async/await與Promise的結果一樣,但程式碼看起來清晰許多,方便閱讀也方便維護。

參考資料 :
理解JavaScript 的async/await
JavaScript 好用的 async 異步函數!


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言