在 JavaScript 中,Promise 和 setTimeout 是處理非同步操作的兩個重要工具。兩者都用於處理非同步事件,但工作方式和使用場景不同。

Promise

Promise 是 JavaScript 用來處理非同步操作的物件,代表一個可能尚未完成、但未來某個時間點會完成的操作。Promise 有三種狀態:

  1. Pending(進行中):初始狀態,既未完成也未拒絕。
  2. Fulfilled(已完成):操作成功完成。
  3. Rejected(已拒絕):操作失敗。

Promise 的主要優點:

  • 可以將非同步操作以同步流程的方式表達,避免回呼地獄。
  • 提供 .then().catch().finally() 方法,讓處理非同步結果更直觀。

Promise 的基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const myPromise = new Promise((resolve, reject) => {
// 非同步操作
if (/* 操作成功 */) {
resolve(result);
} else {
reject(error);
}
});

myPromise.then(result => {
// 處理成功的結果
}).catch(error => {
// 處理錯誤
});

setTimeout

setTimeout 是一個全域函式,用於在指定毫秒數後執行一段程式碼,是 JavaScript 非同步程式設計的基礎之一。

基本語法:

1
setTimeout(callback, delay);

其中 callback 是要執行的函式,delay 是延遲的毫秒數。

setTimeout 的特性

  1. 非阻塞:setTimeout 不會阻塞程式的執行,它會將回呼函式加入事件佇列,等待執行。
  2. 最小延遲:即使設定延遲為 0,回呼函式也不會立即執行,而是在當前執行堆疊清空後才執行。
  3. 計時器精度:由於 JavaScript 的單執行緒特性和事件循環機制,setTimeout 的實際延遲可能比指定時間長。

Promise 和 setTimeout 的結合使用

兩者可以結合,建立一個在指定時間後 resolve 的 Promise:

1
2
3
4
5
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

delay(2000).then(() => console.log('2 秒後執行'));

事件循環和執行順序

理解 Promise 和 setTimeout 的執行順序,需要掌握 JavaScript 的事件循環機制:

  1. 同步程式碼優先執行。
  2. 微任務(如 Promise 的 then/catch/finally)在當前任務結束後立即執行。
  3. 宏任務(如 setTimeout、setInterval)在下一次事件循環中執行。

來看這個範例:

1
2
3
4
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');

輸出順序是:1, 4, 3, 2

  • '1''4' 是同步程式碼,立即執行。
  • Promise.then 是微任務,同步程式碼執行完後立即執行。
  • setTimeout 是宏任務,排到下一次事件循環才執行。

結論

Promise 提供更靈活的方式來處理非同步結果,setTimeout 則用於延遲執行程式碼。清楚理解這兩者在事件循環中的行為,是寫出可預期 JavaScript 的基礎。