JavaScript – Async, Await

前言

前接JavaScript – PromisePromise提供了一個異步操作的方式,但寫法仍然略為複雜;而asyncawait就是為了簡化Promise而產生的。

asyncawait簡介

先簡單說明asyncawait

async

  1. 加在function之前。
  2. function會自動被包成一個Promise來執行。
  3. 若有return值,會被放在Promise.resolve裡再回傳

await

  1. 僅能用在有加asyncfunction之中。
  2. 對象是PromiseThenable
  3. 會等待Promise執行完再繼續執行後續的程式。

實例

以一個經常使用的場景來說明,在畫面載入大量資料時,會先使用圖示或文字在畫面上提示Loading並將系統變為載入中的狀態,然後透過AJAX取得資料後顯示資料,再通知系統變為載入完成的狀態,以便去除載入圖示或文字。

基本想法

上述的場景,如果寫成程式可能是下列這樣子

function normalLoadTodos() {
    console.log("1. ---Normal Loading---");
    fetch(API)
        .then(response => response.json())
        .then(data => {console.log("2. Normal [Data] - "+data)});
    console.log("3. ---Normal Loading Finished---");
}

但實際執行的結果可能會是

1. ---Normal Loading---
3. ---Normal Loading Finished---
2. Normal [Data] - [object Object]

步驟2因為是異步執行,所以比較慢,而步驟3已經做完了,造成去除了載入文字但沒有資料可用的問題。

使用then

根據上面的問題,很快就想到,如果把步驟3放在步驟2的then裡,就可以解決了。

function normalLoadTodos2() {
    console.log("1. ---Normal Loading---");
    fetch(API)
        .then(response => response.json())
        .then(data => {console.log("2. Normal [Data] - "+data)})
        .then(()=> console.log("3. ---Normal Loading Finished---"));
}

的確,執行的結果就會如我們所想,依序執行

1. ---Normal Loading---
2. Normal [Data] - [object Object]
3. ---Normal Loading Finished---

但如果在fetch後續有很多行程式呢?那then就會一直then下去囉。

改用async及await

再來就看看asyncawait能簡化程式到什麼樣的地步

async function asyncLoadTodos() {
    console.log("1. ---Async Loading---");
    await fetch(API)
        .then(response => response.json())
        .then(data => {console.log("2. Async [Data] - "+data)});
    console.log("3. ---Async Loading Finished---");
}

第一步,在function前加上async

async function asyncLoadTodos() {
    ....
}

第二步,在fetch前加上await

async function asyncLoadTodos() {
    ...
    await fetch(API)
    ...
}

因為fetch會回傳Promise物件,所以是await可用的對象,而要用await,在外層的function必需要加上async

而執行結果就如預期般地依序執行

1. ---Async Loading---
2. Async [Data] - [object Promise]
3. ---Async Loading Finished---

再簡化

觀察一下,可以發現fetch後的then,都沒有異步執行的問題,所以可以再拿出來

async function asyncLoadTodos2() {
    console.log("1. ---Async Loading---");
    let response = await fetch(API);
    let data = response.json();
    console.log("2. Async [Data] - "+data);
    console.log("3. ---Async Loading Finished---");
}

把所有then都移除了,看起來的確容易多囉。

比較

比較兩種版本

function normalLoadTodos2() {
    console.log("1. ---Normal Loading---");
    fetch(API)
        .then(response => response.json())
        .then(data => {console.log("2. Normal [Data] - "+data)})
        .then(()=> console.log("3. ---Normal Loading Finished---"));
}

async function asyncLoadTodos2() {
    console.log("1. ---Async Loading---");
    let response = await fetch(API);
    let data = response.json();
    console.log("2. Async [Data] - "+data);
    console.log("3. ---Async Loading Finished---");
}

哪一種比較容易懂呢?

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料