嗨大家好,今天要來聊Async / Await。
在講async/await之前,先簡單回顧一下「非同步」這件事。
JavaScript 的程式碼通常是在單一執行緒上執行,但我們常常需要做一些「要等一下才會有結果」的事情,例如:
setTimeout)這些操作如果用「同步」的方式寫,程式就會卡住不動,使用者體驗會很差。所以早期我們會用 Callback(回呼函式) 來處理:
getUser(id, (user) => {
getOrders(user.id, (orders) => {
getOrderDetail(orders[0].id, (detail) => {
console.log(detail);
});
});
});
後來ES6引入了 Promise,改善了Callback的結構,讓程式更簡潔:
getUser(id)
.then((user) => getOrders(user.id))
.then((orders) => getOrderDetail(orders[0].id))
.then((detail) => console.log(detail))
.catch((err) => console.error(err));
但當邏輯變複雜(例如:加上if/else、迴圈)時,.then() 串接還是會讓程式碼變得不直覺。
於是,Async / Await 就誕生了!它是ES2017(ES8)加入的語法糖,讓我們可以用「看起來像同步」的方式,寫非同步程式碼。
async:宣告在函式前面,代表這是一個「非同步函式」,它的回傳值一定會被包成一個 Promise。await:只能用在async函式內部,當程式執行到await時,會暫停目前async函式後面的程式碼,等Promise有結果後再繼續執行。把上面 Promise 的例子改寫成 async/await:
async function getOrderDetailFlow(id: string) {
const user = await getUser(id);
const orders = await getOrders(user.id);
const detail = await getOrderDetail(orders[0].id);
console.log(detail);
}
如果你只是寫JavaScript,async/await就已經很好用了;但套用到TypeScript,型別系統會幫你把非同步的「回傳值型別」也顧好。
async函式的回傳型別一定是Promise<T>async function getUserName(id: string): Promise<string> {
const user = await getUser(id);
return user.name; // 型別是 string
}
就算你在函式內return user.name,TS也會自動把回傳型別包裝成Promise<string>,因為 async函式本質上就是回傳一個Promise。
await會自動解包Promise的型別async function fetchOrders(): Promise<Order[]> {
const response = await fetch("/api/orders"); // response: Response
const data: Order[] = await response.json(); // data: Order[]
return data;
}
這邊 await的效果,就是把 Promise<Order[]> 轉成 Order[],不用再手動處理 .then() 拆值,型別也會跟著正確推導。
在Promise中,我們用 .catch() 處理錯誤;在async/await的世界,直接用try / catch就可以了:
async function loadUser(id: string) {
try {
const user = await getUser(id);
console.log(user);
} catch (error) {
console.error("讀取使用者失敗:", error);
} finally {
console.log("不管成功失敗,這裡都會執行");
}
}
在TypeScript中,catch抓到的error預設型別是unknown,使用前建議先做型別收窄:
catch (error) {
if (error instanceof Error) {
console.error(error.message);
}
}
Async/Await可以說是現在前端開發中很常見的非同步寫法,尤其是在打API、串接後端服務時很常看到。今天的內容就到這邊啦!各位明天見!