iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
JavaScript

JS 核心重構:勇者轉職傳說系列 第 20

Day 19:【圖解】為什麼程式不乖乖排隊?JS 腦袋裡的 Event Loop

  • 分享至 

  • xImage
  •  

本文同步分享於個人部落格:Liwen Chiou | Digital Architect & Full-Stack Engineer


📜 這裡的修煉規則:

孩子,在踏上今日的領地前,先坐下來喝杯酒吧。
修煉的路很長,別急著奔跑,先聽聽這份卷軸裡的古老叮嚀。

我在每一站的盡頭都為你鋪設了 實戰演武場 CodePen。那不只是程式碼的拼湊,而是你在這場暴風雨中,試圖用邏輯點燃的一顆星火。
成功突圍後,別忘了帶著你的戰利品回到 QuestBoard 佈告欄。在那裡,你會發現自己從不孤單,公會的夥伴們都正舉杯等待你的歸來。

記住...

導師看重的從來不是你的劍法有多華麗,而是當你被邏輯擊潰、滿身泥濘後,依然選擇握緊理性的劍柄,再次向真相發起衝鋒的勇氣。


🛡️ 【公會大廳:導師的修煉導讀】

「導師,這不可能!我明明在第一行寫了 setTimeout(..., 0),為什麼它卻在我最後一行的 console 之後才印出來?0 秒難道不是立刻嗎?」

我放下手中的羽毛筆,看著眼前焦慮的新手冒險者。

「孩子,這就是 JavaScript 最誠服也最神祕的本質。它是一個 『單線跑者』。即便你給他一百個任務,他的大腦一次也只能思考一件事。今天,我們要潛入 JS 的思維深處,看看那位忙碌的 『辦事員』 是如何與 『自動販賣機 (Web APIs)』 以及 『排隊區 (Queue)』 協作,才不至於讓整個網頁崩潰。」

這章節,我們不學語法,我們要學「看清時間的流向」。


💡 【導師講義:底層真相探究】

1. 單線跑者:一次只能做一件事

JavaScript 的核心引擎(Call Stack)就像一個狹窄的單向櫃檯。不論是運算、選取 DOM、還是跑迴圈,辦事員一次只能處理一個動作。

如果有一個任務太耗時(例如:去圖書館查閱一萬卷宗),辦事員如果停下來等,整個公會(網頁)就會像凍結了一樣,誰也點不動。

2. 時空分身:辦事員與自動販賣機

為了不讓櫃檯卡死,JS 發展出一套聰明的機制:

  1. 櫃檯 (Call Stack):正在處理的當前任務。
  2. 自動販賣機 (Web APIs):計時器、網路請求、DOM 事件。這些是「耗時」或「等待」的任務。
  3. 排隊區 (Task Queue):完成等待後,準備結算的任務。

🏹 導師的辨析圖:執行順序預測

動作 代碼類型 處理地點
console.log 同步任務 立即在櫃檯執行
setTimeout 非同步任務 送往販賣機計時,跑完後去排隊區
for 迴圈 (百萬次) 阻塞任務 強佔櫃檯,直到跑完為止

3. 本日圖解心法:單手辦事員的極限

導師的圖解心法: 想像辦事員只有一隻手。他遇到 setTimeout 時,會先把計時器丟給旁邊的「自動販賣機」代管。只有當他的櫃檯完全清空 (Stack Empty) 時,他才會轉頭看向「排隊區」,把排在第一位的任務抓回櫃檯執行。這就是為什麼 setTimeout(..., 0) 依然要排隊。

Event Loop 原理圖


⚔️ 【戰術對抗:學長與學弟的代碼對決】

招式示範:預測輸出順序

console.log("A: 開始修煉"); // 同步
setTimeout(() => {
  console.log("B: 計時炸彈爆了"); // 非同步
}, 0);
console.log("C: 結束修煉"); // 同步

❌ 冒險學弟:直覺式解讀 (以為代碼會乖乖由上而下執行)

  • 錯誤直覺輸出順序:A -> B -> C

✅ 勇者學長:底層式解讀 (看清排隊機制的真身)

  • 正確輸出順序:A -> C -> B

導師講評: 為什麼 C 會比 B 快?因為 B 被丟進了「計時販賣機」,即便只有 0 秒,他也要在「排隊區」等辦事員處理完剩餘的 C 之後,才有機會回到櫃檯。


🏰 【勇者精英課:邁向職人的進階架構】

阻塞 (Blocking) 的大危機

如果你寫了一個 for (let i=0; i<1000000000; i++),辦事員會在那裡死命地數數,這段時間他無法轉頭看「排隊區」,也無法處理任何使用者點擊。這就是為什麼網頁會出現「程式沒有回應」的原因。

職人金句: 絕不要在櫃檯做太久的體力活,學會把重體力活拆散,或是交給非同步處理。


🛖 【營火叮嚀:導師的經驗談】

孩子,導師當年以為 setTimeout(..., 1000) 真的是「精準 1 秒後執行」。
結果那次我的櫃檯正忙著處理一個巨大的地圖檔案,處理了 3 秒,導致我的計時器在 4 秒後才印出來。

記住:JavaScript 的時間不是準確的約定,它只是「最快何時能跑」的保證。


天色微亮,營火雖已燃盡,但你眼中卻閃爍著領悟的光芒。在前往演武場挑戰關卡前,我已經幫你把靈魂碎片精煉成了這份「戰術錦囊」。拿好它,今日的任務不再是負擔,而是你證明自我的舞台。去吧,公會的英雄榜在等著你的戰報。

📝 【夥伴筆記:今日修煉精華】

  • Single Threaded:JS 大腦一次只能處理一件事。
  • Call Stack:目前的櫃檯,同步任務都在這。
  • Task Queue:非同步任務排隊領號碼牌的地方。
  • Event Loop:負責檢查櫃檯是否清空,並從門口拉人進來的守衛。

🎯 【實戰演武場】

⚔️ 任務鑑定條件:

  1. 完成 📜 本日實戰任務 (CodePen)
  2. 將 CodePen 網址貼至 QuestBoard,並回填鑑定報告:
    • 初心者:時空裂縫預測 (成就感發掘)
        1. 如果你在 setTimeout 裡面再寫一個 setTimeout,誰會先跑?
    • 冒險者:阻塞的代價 (理性挑戰)[⚡ 觀念辨析]
        1. 你能理解為什麼 alert() 會讓整個網頁的所有計時器都暫停嗎?(因為它強佔了哪一個區塊?)

📚 【圖書館卷軸:延伸學習】


上一篇
Day 18:【期中實戰】純 JS 打造你的第一個「任務佈告欄」
系列文
JS 核心重構:勇者轉職傳說20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言