介紹
大家好!
今天,正如標題所說,我將討論事件循環。
這不是面試官經常直接詢問的話題(我只記得有兩次他們讓我解釋事件循環)。但是,在大多數採訪中,他們會提出與之相關的問題。例如:
- “如果我這樣做…應該有什麼行為?”
- “如果我的程式碼如下所示,輸出會是什麼?”
- “為什麼這段程式碼會產生這樣的輸出?”
如果您了解事件循環的工作原理,那麼所有這些問題都會更容易回答。
老實說:這個話題不是我最喜歡的。我更喜歡詢問有關程式碼行為的問題,而不是解釋事件循環如何連續工作 10 分鐘。 ?
讓我們開始吧! ?
## 問題
1.什麼是事件循環?
2. 範例
什麼是事件循環?
簡短回答:
事件循環負責處理 JavaScript 執行階段中的非同步任務。
說實話,我認為這個答案不足以滿足面試官詢問事件循環的好奇心。因此,在這篇文章中,我想更深入地探討這個主題。
不僅僅是了解概念,了解如何它的工作原理也很重要。這就是為什麼我在最後添加了一些示例。
理論
什麼是事件循環?
JavaScript 有一個基於事件循環的執行時間,負責處理任務。每種語言都有獨特的運行時,需要注意的重要一點是 JavaScript 是單執行緒。
單線程是什麼意思?
單執行緒意味著JavaScript 一次只能處理一項任務。這就是為什麼事件循環在 JavaScript 中如此重要;儘管存在單執行緒限制,它仍然有助於有效地管理任務。
運行時的組成部分
為了更好地理解事件循環,我們先來看看它的主要組成部分:
呼叫堆疊
呼叫堆疊是一種資料結構,用來追蹤我們所呼叫的函數。你可以把它想像成一堆盤子:當一個函數被呼叫時,它被加到堆疊中,當它完成時,它被從堆疊中刪除。
呼叫堆疊遵循LIFO(後進先出) 原則,這意味著JavaScript 按照函數的堆疊順序執行函數— 從最上面的項目到底部,一個位於一次(記住,JavaScript 是單線程的)。
佇列
在 JavaScript 的執行時間中,我們有佇列,它保存要處理的任務清單。這些佇列中的任務會等待,直到呼叫堆疊為空。
任務佇列(或回調佇列):此佇列儲存諸如 setTimeout() 和 setInterval() 呼叫之類的任務。這裡的任務是在呼叫堆疊為空並且微任務佇列中的所有任務都處理完之後進行處理的。在 MDN 上查看儲存在此佇列中的任務的更多範例。
微任務佇列: 此佇列的優先權高於任務佇列。它包括微任務(例如 Promise 回調)和非同步函數(例如 process.nextTick() 和非同步函數)。
任務佇列以FIFO(先進先出)為基礎工作,這表示任務按照新增的順序進行處理,但僅在微任務之後進行佇列已空。
事件循環
事件循環是一種管理非同步程式碼執行的機制。它觀察呼叫堆疊以及呼叫堆疊和佇列(任務佇列和微任務佇列)之間的協調,以保持程式碼順利運行。
它是如何運作的?
讓我們一步步過一遍事件循環過程。請參閱下圖以獲得直觀表示。
在此範例中:
- 呼叫堆疊只有一個函數。
- 微任務佇列有兩個訊息。
- 任務佇列有訊息。
第 1 步:處理呼叫堆疊
- 事件循環從查看呼叫堆疊開始。
- 它在堆疊中找到一個函數並開始執行它。
- 此函數完成後,就會從呼叫堆疊中刪除。
步驟2:處理微任務隊列
- 呼叫堆疊為空後,事件循環會檢查微任務佇列。
- 它從微任務佇列取得第一個訊息並將其推送到呼叫堆疊來執行。
- 函數運行,一旦完成,就會從呼叫堆疊中刪除。
- 事件循環然後移動到微任務佇列中的下一則訊息並重複此過程。
- 這會持續到微任務佇列中不再有消息為止。
第三步:處理任務隊列
- 一旦呼叫堆疊和微任務佇列都為空,事件循環就會轉向任務佇列。
- 它選擇任務佇列中的第一個訊息並將其新增至呼叫堆疊。
- 函數運行,完成後,它會從呼叫堆疊中刪除。
- 事件循環將對任務佇列中的每個任務繼續此過程,確保所有任務都被一一處理。
依照這個順序-呼叫堆疊,然後微任務佇列,最後任務佇列-事件循環幫助JavaScript有效處理非同步程式碼,即使在它的單線程環境。
範例
現在我們了解了事件循環的工作原理以及任務的優先順序如何確定,讓我們來看一些範例。
實施例1
const a = new Promise(function showA(resolve){ console.log('A'); resolve('B'); }); setTimeout(function showC() { console.log('C'); }, 0); a.then(function showB(b) { console.log(b); }); const d = function showD() { console.log('D'); }; d();
在繼續之前,試著考慮一下輸出的順序。
✨你期望它是什麼? ✨
讓我們分解程式碼的每個部分來理解為什麼我們會得到這個輸出。
1。創造承諾
const a = new Promise(function showA(resolve) { console.log('A'); resolve('B'); });
- 在這裡,我們建立一個帶有回調函數的新 Promise。
- 在此函數內,console.log('A') 會立即執行,因此 "A" 會列印到控制台。
- 記錄「A」後,promise 被解析為值「B」。
- JavaScript 識別出有一個.then 回調(即showB),一旦主調用堆疊清除,該回調應該運行,因此它將showB 添加到微任務隊列(因為Promise 解析會去那裡) 。
2。 setTimeout 呼叫
setTimeout(function showC() { console.log('C'); }, 0);
- setTimeout 函數安排 showC 在 0 毫秒後運行。
- JavaScript 將 showC 放入任務佇列中,因為它是一個基於計時器的函數。
3。 a.then 回呼
const a = new Promise(function showA(resolve){ console.log('A'); resolve('B'); }); setTimeout(function showC() { console.log('C'); }, 0); a.then(function showB(b) { console.log(b); }); const d = function showD() { console.log('D'); }; d();
- 這行為我們在上一個步驟中已經解決的 Promise 註冊了一個 .then 處理程序 (resolve('B'))。
- 由於 Promise 已解決,showB(.then 回調)被加入到 微任務佇列。
4。定義 d
const a = new Promise(function showA(resolve) { console.log('A'); resolve('B'); });
- 這一行只是定義了函數 showD 但尚未執行它,所以這裡什麼也沒有發生。
5。呼叫 d()
setTimeout(function showC() { console.log('C'); }, 0);
- 現在,我們呼叫 d(),它被加到 呼叫堆疊 並執行。 這會產生 console.log('D'),因此 "D" 會列印到控制台。
最終輸出順序:
a.then(function showB(b) { console.log(b); });
GIF供參考
互動範例
實施例2
const d = function showD() { console.log('D'); };
再花點時間考慮輸出的順序。
✨你期望它是什麼? ✨
讓我們來解釋一下......
1。記錄「開始!」
d();
- 這行程式碼被加到呼叫堆疊並立即執行。
- 結果,「開始!」 被印到控制台。
- 設定超時調用
A D B C
- setTimeout 函數安排 showTimeout 在 0 毫秒後運行。
- JavaScript 將 showTimeout 放置在 任務佇列 中,因為它是一個基於計時器的函數。
3。承諾決議
console.log("Start!"); setTimeout(function showTimeout() { console.log("Timeout!"); }, 0); Promise.resolve("Promise!") .then(function showPromise(res) { console.log(res); }); console.log("End!");
- 承諾立即解決,值為「Promise!」。
- JavaScript 將 showPromise(.then 回呼)放入 微任務佇列,因為 Promise 在解析後會進入微任務佇列。
4。記錄「結束!」
console.log("Start!");
- 這行程式碼被加到呼叫堆疊並立即執行。
- 結果,「結束!」 被印到控制台。
最終輸出順序:
setTimeout(function showTimeout() { console.log("Timeout!"); }, 0);
GIF供參考
互動範例
結尾
本章並不太長,但我希望這些範例可以幫助您理解事件循環的工作原理。
我強烈建議嘗試互動頁面來分析其他範例。在該頁面上進行操作可以更輕鬆地理解正在運行的事件循環。
非常感謝大家對我之前貼文的喜愛!
下週見! ?
再見
以上是技術面試問題 - 部分事件循環的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript核心數據類型在瀏覽器和Node.js中一致,但處理方式和額外類型有所不同。 1)全局對像在瀏覽器中為window,在Node.js中為global。 2)Node.js獨有Buffer對象,用於處理二進制數據。 3)性能和時間處理在兩者間也有差異,需根據環境調整代碼。

JavaScriptusestwotypesofcomments:single-line(//)andmulti-line(//).1)Use//forquicknotesorsingle-lineexplanations.2)Use//forlongerexplanationsorcommentingoutblocksofcode.Commentsshouldexplainthe'why',notthe'what',andbeplacedabovetherelevantcodeforclari

Python和JavaScript的主要區別在於類型系統和應用場景。 1.Python使用動態類型,適合科學計算和數據分析。 2.JavaScript採用弱類型,廣泛用於前端和全棧開發。兩者在異步編程和性能優化上各有優勢,選擇時應根據項目需求決定。

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。