iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0
自我挑戰組

JS 加強筆記系列 第 21

Day 21:async/ await (1)

  • 分享至 

  • xImage
  •  

async function

async 加在函式前面,代表這個函式一定會回傳 promise。也就是撰寫時可以在函式內明確回傳 promise,或是當回傳其他值時,該值會被包成一個 resolved promise:

async function f() {
    return 1;
}

f().then(res => {
    console.log(res); // 1
});

await

await 只能用在 async function 裡。當 await 放在 promise 前面,會等待那個 promise 完成、回傳結果。換句話說它用比較直覺的語法做原本 then 做的事情:

async function f() {
    let result = await new Promise((resolve, reject) => {
        setTimeout(() => resolve('done!'), 1000)
    });
    console.log(result); // done!
}

f();

關於 await 的小補充

雖然大部分時候 await 被用來等待 promise ,但它並不限定後面只能接 promise,如同 MDN 的描述:await expression 中的 expression 可以是 'A Promise, a thenable object, or any value to wait for.'。當表達式不為 promise 時,await 會把其值轉為一個 resolved promise 然後一樣等待它:

async function f3() {
    const y = await 20;
    console.log(y); // 20
}

f3();

雖然這樣貌似什麼事都不會發生,取到的值也沒變,但實際上還是有一些影響。因為 await 執行後 control 會回到呼叫函式的地方,而 await 以下「要等待結果的程式碼」會被放進 microtask queue 等待 (有點像 then() 無論是否已有結果都會非同步執行),所以會造成程式碼執行順序改變,像下方執行兩遍的 'end' 部分都會被往後排:

async function foo(name) {
  console.log(name, "start");
  await console.log(name, "middle");
  console.log(name, "end");
}

foo("First");
foo("Second");

// First start
// First middle
// Second start
// Second middle
// First end
// Second end

也因為這樣的特性,建議只有在真的要等待 promise 回傳值的情境才使用 await,以免出現意外的結果。這個問題也有類似的例子可以參考。

改寫

這裡是嘗試把之前寫到的 fetch 範例寫成 async/ await 版本,看起來已經非常像一般的同步程式碼,幾乎沒有視覺跳躍的地方,像最後 setTimeout 的部分可以把程式碼拆得更乾淨,每個步驟按照順序做單一的工作:

async function loadJson(url) {
    const response = await fetch(url);
    const resJson = await response.json();
    return resJson;
}

async function showAvatar() {
    const user = loadJson('/article/promise-chaining/user.json');
    const githubUser = loadJson(`https://api.github.com/users/${user.name}`);
    
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);
    
    await new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve();
        }, 3000);
    })
    
    img.remove();
}

上一篇
Day 19:promisification (2)
下一篇
Day 22:async/ await (2)
系列文
JS 加強筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言