跳至主要内容

Node Promise

📌 1. 基本概念

Promise 是 ES6 引入的非同步編程解法,用來避免 callback hell。

一個 Promise 物件表示一個尚未完成但預期會完成的操作結果。

狀態說明
pending初始狀態,尚未結束
fulfilled操作成功完成(resolve)
rejected操作失敗(reject)
const promise = new Promise((resolve, reject) => {
if (someCondition) resolve('成功');
else reject('錯誤');
});

📌 2. Promise 執行順序與事件循環(Event Loop)

類型分類優先順序
.then, .catch, .finallyMicrotask高(在 macrotask 後立即執行)
setTimeout, setImmediateMacrotask較低
console.log('start');

setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('end');

✅ 預期輸出:

start
end
promise
timeout

📌 3. async/await 是怎麼實現的?

  • async 函數本質上會回傳一個 Promise。
  • await 會暫停該函數執行,等待 Promise resolve,再繼續執行後續程式。
async function main() {
console.log('1');
await Promise.resolve();
console.log('2');
}
main();
console.log('3');

✅ 預期輸出:

1
3
2

❗ await 會將後續程式包進 microtask queue!

📌 4. 常見面試題與解析

🧠 Q1:Promise 是如何與事件循環互動的?

✅ 建議答法:

Promise 的 .then、.catch 屬於 microtask,在當前事件循環的 macrotask 結束後會立即被執行。這保證了非同步操作的順序性與預測性,也避免 blocking 主執行緒。


🧠 Q2:以下程式碼輸出順序為?

Promise.resolve().then(() => {
console.log('A');
Promise.resolve().then(() => {
console.log('B');
});
});

✅ 預期輸出:

A
B

✅ 原因:

第一個 .then() 進入 microtask queue,執行時註冊第二個 .then(),然後下一輪 microtask queue 才執行 B。


🧠 Q3:為何 Promise 被稱為 "微任務"(microtask)?

✅ 建議答法:

因為它在每個事件循環(tick)結束後、進入下一個 macrotask 之前執行。這使得它具有比 setTimeout 等 macrotask 更高的優先級,能即時處理非同步邏輯。


🧠 Q4:Promise.all 和 Promise.race 差異?

方法說明使用場景
Promise.all所有都 fulfilled 才成功,任一 reject 則整體失敗多個 API 要成功
Promise.race最快的 promise 決定結果(無論成功或失敗)超時處理
Promise.race([
fetch('/slow-api'),
new Promise((_, reject) => setTimeout(() => reject('timeout'), 3000))
])

🧠 Q5:如何將 callback 函式封裝成 Promise?

const fs = require('fs');
const { promisify } = require('util');

const readFile = promisify(fs.readFile);
readFile('./test.txt', 'utf-8')
.then(data => console.log(data))
.catch(err => console.error(err));

📘 延伸學習資源