2.1 非同步程式設計#
為什麼 Node 的程式碼「不會等」?#
還記得 1.1 節的事件迴圈嗎?Node 遇到 I/O 不會停下來等,所以你需要一種機制來描述「完成之後要做什麼」。這個機制演進了三代:
callback(回呼) → Promise → async/await(現代標準)
第一代:callback(回呼函式)#
把「完成後要做的事」當成參數傳進去:
const fs = require("node:fs");
fs.readFile("data.txt", "utf8", (err, data) => {
if (err) {
console.error("讀檔失敗", err);
return;
}
console.log(data);
});
console.log("這行會先印出來!"); // 不等讀檔,先執行
問題:多個非同步步驟要依序執行時,會出現回呼地獄:
getUser(id, (err, user) => {
getOrders(user, (err, orders) => {
getDetails(orders[0], (err, details) => {
// 縮排越來越深,程式碼變成金字塔
});
});
});
第二代:Promise#
Promise 代表「一個未來才會完成的結果」,用 .then 串接:
fetch("https://api.example.com/user")
.then(res => res.json())
.then(user => console.log(user))
.catch(err => console.error(err)); // 錯誤統一處理
第三代:async/await(現代標準,必學)#
用「看起來同步」的寫法處理非同步:
async function main() {
try {
const res = await fetch("https://api.example.com/user");
const user = await res.json();
console.log(user);
} catch (err) {
console.error(err); // 用熟悉的 try/catch 處理錯誤
}
}
main();
規則:
await只能用在async函式裡await會「等 Promise 完成」再繼續往下執行- 錯誤用
try/catch接住
平行執行多個非同步工作:用 Promise.all,全部完成才繼續:
const [user, orders] = await Promise.all([
fetchUser(id),
fetchOrders(id),
]);
心法:新程式碼一律用
async/await;讀舊程式碼要看得懂 callback 和.then。