簡要說明 JavaScript 的 Event Loop
JavaScript 是單執行緒 (single-threaded) 語言,這意味著它一次只能執行一件事,因此所有函式都需要排隊等待執行,這被稱為同步 (synchronous)。在同步操作中,若函式過多或過於複雜,會導致程式阻塞 (blocking),網頁卡住。
為了解決阻塞問題,JavaScript 引入了非同步 (asynchronous) 機制,允許程式碼並發 (concurrency) 運作。非同步操作避免了阻塞,使網頁更加順暢。非同步的運作涉及三個主要部分:Call stack、Web API 和 Callback queue。
- Call stack:追蹤呼叫的函式,處理同步任務。
- Web API:處理非同步任務(如 setTimeout),並將完成的任務送到 Callback queue。
- Callback queue:存放已完成的非同步任務,等待重新進入 Call stack。
Event loop 是個守衛,不斷檢查 Call stack 是否為空。如果 Call stack 為空,它會將 Callback queue 中的回調函式 (callback function) 移回 Call stack 中執行。
這樣,JavaScript 能在單執行緒的基礎上處理非同步任務,保持網頁的流暢性。
那我們來看一下例子
console.log(‘hi’);
setTimeout(function cb(){
console.log(‘there’);
}, 5000);
console.log(‘JSConfEU’)
產出結果順序將會是 :
'hi''JSConfEU''there'
步驟解析
- 執行
console.log('hi')這是一個同步操作,直接在主線程上執行,並立即輸出 "hi" - 執行
setTimeout(function cb(){console.log('there')},5000):setTimeout 是一個非同步操作。它會安排一個計時器,並將回調函式 cb 註冊到 Web API 中,計時5000毫秒(5秒)。此時,計時器開始倒數計時,並將回調函式 cb 放到 Web API 中,等待計時結束。註冊計時器的操作是同步的,所以立即返回,並繼續執行接下來的程式碼。

- 執行
console.log('JSConfEU')這是一個同步操作,直接在主線程上執行,並立即輸出 "JSConfEU"

- 5秒後,計時器完成,回調函式 cb 被移至 Callback queue 中:Event loop 檢查到 Call stack 為空,將回調函式 cb 移入 Call stack 中執行。執行
console.log('there'),並輸出 "there"

Callback Function
Callback 是一種將函式 B 作為參數傳遞給函式 A 的方式,透過函式 A 在適當的時候執行函式 B。這樣做的目的是控制函式執行的順序,通常在需要滿足特定條件後才執行函式 B。
function greet(name, callback) {
console.log("Hello, " + name);
callback();
}
function sayGoodbye() {
console.log("Goodbye!");
}
greet("Alice", sayGoodbye);
- greet 函式:接受一個名字和一個回調函式,首先打印 "Hello, [名字]",然後執行回調函式。
- sayGoodbye 函式:只打印 "Goodbye!"
- 呼叫 greet:傳遞名字 "Alice"和回調函式 sayGoodbye,先打印 "Hello, Alice",接著打印 "Goodbye!"
Promise
如果按照Callback剛剛這樣執行的話,會造成函式層層嵌套,而 Promise 解決了這個問題,使程式更易讀。
Promise 有三種狀態:
- Pending:進行中
- Resolve:成功
- Reject:失敗
Promise 通常使用 .then() 來處理成功,.catch() 來處理失敗。
如果把剛剛callback寫成promise的話,會像這樣:
function greet(name) {
return new Promise((resolve, reject) => {
if (!name) {
reject("錯誤");
} else {
console.log("Hello, " + name);
resolve();
}
});
}
function sayGoodbye() {
console.log("Goodbye!");
}
greet("Alice")
.then(() => {
sayGoodbye();
})
.catch(error => {
console.error("Error:", error);
});
可以更清晰地控制函式的執行順序。
async/await
async/await 是基於 Promise 的語法糖,使非同步程式碼看起來像同步執行。
- async:定義一個非同步函式。
- await:等待 Promise 完成,就像同步程式碼一樣。
這樣寫法更簡潔,不需要 .then,錯誤處理用 try 和 catch。
function greet(name) {
return new Promise((resolve, reject) => {
if(!name){
reject('錯誤')
} else {
console.log("Hello, " + name);
resolve();
}
});
}
function sayGoodbye() {
console.log("Goodbye!");
}
async function main() {
try {
await greet("Alice");
sayGoodbye();
} catch (error) {
console.error("Error:", error);
}
}
main();


















