今天我們將放慢腳步,回歸到非同步程式設計的起點,專注於一個看似簡單,卻蘊含深意的關鍵字:async
。
在前幾天的內容中,我們為了快速理解整個流程,將 async/await
視為一個密不可分的整體來學習。這種方法有助於我們快速建立宏觀概念,但魔鬼往往藏在細節裡。今天,我們要像偵探一樣,把它們暫時拆開,單獨審視 async
。
我們要徹底搞清楚:當我們在一個函式前面,輕輕地加上 async
這個詞,到底對這個函式施了什麼魔法?它為什麼被稱為「語法蜜糖」?它又為什麼是所有 await
操作不可或缺的前提?
今天的目標非常純粹:徹底理解 async
函式的本質。學完今天,你將會明白 async
如何將任何一個普通函式,都轉變為一個「承諾未來的 Promise 製造機」,並為我們明天重新學習 await
打下最堅實的地基。
async
的黃金法則關於 async
函式,你只需要記住一條顛撲不破的黃金法則:
async
函式,永遠、永遠、永遠,回傳一個 Promise。
無論你在函式內部做了什麼,是回傳一個數字、一個字串,還是什麼都不回傳,只要你在 function
前面加上了 async
,這個函式的回傳值必定是一個 Promise 物件。
async
如何包裝回傳值async
這個關鍵字就像一個自動化的「Promise 包裝工廠」。讓我們看看它是如何處理不同情況的。
讓我們定義一個最簡單的 async
函式,它只回傳一個字串。
// 在 function 前面加上 async
async function sayHello() {
return 'Hello, World!';
}
// 呼叫這個函式,並看看回傳的是什麼
const result = sayHello();
console.log(result);
打開開發者工具的 Console,你會看到驚人的結果:
Promise {<fulfilled>: "Hello, World!"}
我們並沒有手動建立 Promise,但 result
卻是一個 Promise!
魔法解析:JavaScript 引擎看到 async
關鍵字,它就在內部自動幫我們做了這件事:它拿到了 'Hello, World!'
這個普通字串,然後把它打包成一個已經完成 (fulfilled) 的 Promise 再回傳出來。
如何取出裡面的值? 既然回傳的是 Promise,我們就可以用之前學過的 .then()
來取得結果:
sayHello().then(value => {
console.log('用 .then() 取出的值:', value); // 輸出: 用 .then() 取出的值: Hello, World!
});
如果 async
函式在執行過程中出錯了呢?
async function somethingGoesWrong() {
console.log('這行會執行...');
throw new Error('糟糕,出錯了!');
// console.log('這行永遠不會執行');
}
const errorResult = somethingGoesWrong();
console.log(errorResult);
再次查看 Console,你會看到:
這行會執行...
Promise {<rejected>: Error: 糟糕,出錯了!}
同時,瀏覽器可能還會印出一個未被捕獲的錯誤訊息。
魔法解析:async
函式非常聰明。它內建了 try...catch
的機制。當它發現函式內部拋出了錯誤,它會自動捕獲這個錯誤,然後將它打包成一個已經被拒絕 (rejected) 的 Promise 回傳出來。
如何處理這個錯誤? 同樣地,我們可以使用 .catch()
來優雅地處理這個被拒絕的 Promise:
somethingGoesWrong().catch(error => {
console.error('用 .catch() 捕獲的錯誤:', error.message); // 輸出: 用 .catch() 捕獲的錯誤: 糟糕,出錯了!
});
async
?既然 async
只是把東西包裝成 Promise,我們為什麼不自己手動包裝呢?async
作為「語法蜜糖」,到底甜在哪裡?
語意清晰,提升可讀性 當你在一個函式簽名上看到 async
,它就像一個醒目的路標,立刻告訴閱讀程式碼的人(包括未來的你):「注意!這個函式內部包含了非同步邏輯,它的回傳值是一個 Promise,請用非同步的方式來處理它。」這讓程式碼的意圖一目了然。
為 await
創造了唯一的「合法環境」 這是 async
最最重要、無可替代的作用。我們將在明天深入探討的 await
關鍵字,有一個非常嚴格的規定:
await
只能在async
函式內部使用。
你可以把 async
函式想像成一個特殊的「異次元空間」,只有在這個空間裡,時間才可以被 await
「暫停」。async
關鍵字的作用,就是開啟這個空間的「傳送門」。沒有 async
,就沒有 await
。
今天我們進行了一次深入的顯微鏡觀察,專注於 async
這一個關鍵字
現在,我們已經徹底理解了 async
函式這個強大的「容器」。明天,我們將重新拿起它的最佳拍檔——await
關鍵字。
我們將學習如何在 async
函式這個專屬的「異次元空間」中,使用 await
來優雅地「暫停」和「等待」Promise 的結果,並用 try...catch
來確保我們程式的健壯性。
那麼今天的內容就到這邊,感謝你能看到這裡,在這邊祝你早安、午安、晚安,我們明天見。