JavaScript 中的 async/await 是什麼?和 promise 有什麼差別?
2024年3月30日
在之前的文章中
我們分別討論過事件循環 (Event Loop)、異步(非同步) 和 Promise 的概念,而在這篇文章中,我們將深入探討
async/await
是什麼?以及它與 Promise 的差異。
async/await
是什麼?
在 JavaScript 中,
async/await
是一種讓異步(非同步)操作更容易理解和管理的語法。它建立在 Promise 的基礎上,但提供了更簡潔、更直觀的方式來處理異步操作。
以下我們先把
async
和
await
拆開來看:
async
語法
使用
async
關鍵字聲明的函式為異步函式,異步函式會返回一個 Promise 物件,而非直接返回函式執行的結果。讓我們透過範例來了解:
-
下方普通函式
f1()直接返回字串"Hello! ExplainThis!"
// 普通函式
function f1() {
return "Hello! ExplainThis!";
f1(); // 輸出: "Hello! ExplainThis!"
-
下方程式碼中,
async function f2() {...}定義了一個名為f2的異步函式,該函式返回字串"Hello! ExplainThis!",並將其封裝在一個 Promise 物件中。
// 異步函式
async function f2() {
return "Hello! ExplainThis!";
f2(); // 輸出: Promise {<fulfilled>: 'Hello! ExplainThis!'}
上方程式碼寫法跟下方寫法其實是相同的,因為使用
async
時,會自動將回傳值包裝在一個 Promise 物件當中。
// 異步函式
function f3() {
return Promise.resolve("Hello! ExplainThis!");
f3(); // 輸出: Promise {<fulfilled>: 'Hello! ExplainThis!'}
由於
async
函式總是返回一個 Promise 對象,如果要獲取該 Promise 的解析值,可以使用
.then()
方法:
async function f2() {
return "Hello! ExplainThis!";
f2().then((result) => {
console.
log(result); // "Hello! ExplainThis!"
});
await
語法
await
是一個運算子,用於等待一個 Promise 完成或拒絕。它通常與
async
函式一起使用,因為只有在
async
函式內部或模組的頂層,才能使用
await
。
當使用
await
時,程式會暫停執行該
async
函式,直到
await
等待的 Promise 完成並回傳結果後,才會繼續往下執行。讓我們透過下方範例來了解:
async function getData() {
// await 等待 fetch 這個非同步函式返回一個 Promise 並解析它
const res = await fetch("https://example.com/data");
// await 等待上一步的 Promise 解析後,再解析它的 JSON 資料
const data = await res.json();
// 前面兩步都完成後,才會執行這一行並印出資料
console.log(data);
getData();
使用
await
要注意的幾點
-
在非
async函式中使用await會報 SyntaxError 的錯誤
function f() {
let promise = Promise.resolve("Hello! ExplainThis!");
let result = await promise;
// Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
-
頂層
await(Top levelawait)
頂層
await
是一個在 JavaScript 中引入的新語法功能,它允許在模組的最頂層使用
await
關鍵字。在 ES 模組中,原本只有
async
函式內部才能使用
await
。但是使用頂層
await
後,就可以直接在模組頂層使用
await
了。
例如,如果想在某個模組中獲取遠端資源,以前需要這樣寫:
import getData from "./getData.js";
let data;
getData().then((result) => {
data = result;
// ...使用data
});
有了頂層
await
(Top level
await
),你就可以這樣更直接地寫:
const data = await getData();
// ...使用data
如何使用
async/await
?
使用
async/await
可以將異步程式碼寫成類似同步的形式,使其更易讀、且更易維護。讓我們先看一個使用 Promise 寫的 getData 函式範例:
我們先來看用 Promise 來寫一個
getData
函式的例子:
function getData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((res) => res.json())
.then((data) => resolve(data))
.catch((error) => reject(error));
});
getData("https://example.com/data")
.then((data) => console.log(data))
.catch((error) => console.error(error));
在這個例子中,
getData
函式使用 Promise 來處理異步操作。我們需要使用
.then()
和
.catch()
方法來獲取結果或錯誤。
現在,我們使用
async/await
來重寫
getData
函式:
async function getData(url) {
try {
const res = await fetch(url);
const data = await res.json();
console.log(data);
} catch (error) {