我們在名為「Node Internals」的文章中討論了為什麼 Node JS 是單線程的,也是多線程的。它將為您提供 Node 架構的堅實基礎,並為理解事件循環的魔力奠定基礎!
由於事件循環,Node js 可以被認為是單線程的。但是,什麼是事件循環呢?
我總是從餐廳的類比開始,因為我認為這樣比較容易理解技術細節。
所以,在餐廳裡,主廚從訂單清單中取出訂單並將其交給助理團隊。食物準備好後,廚師就會上菜。如果有VIP顧客來,廚師會優先處理這個訂單。
如果我們考慮這個類比,那我們可以說......
在 Node JS 事件循環的上下文中。
Chef 是管理任務和委派工作的事件循環。
協助團隊是一個工作執行緒或作業系統,負責處理委託給他們的任務的執行。
訂單清單是等待輪到的任務的任務隊列。
VIP客戶是一個微任務,優先順序高,先於常規任務完成。
要了解事件循環,我們必須先了解微任務和巨集任務之間的差異。
微任務
微任務是指具有高優先權的任務,並且在目前執行的 Javascript 程式碼完成之後、進入事件循環的下一階段之前執行。
範例:
- process.nextTick
- 承諾(.then、.catch、.finally)
- 隊列微任務
巨集任務
這些是優先順序較低的任務,在事件循環的稍後階段排隊等待執行。
範例:
- 設定超時
- 設定間隔
- 立即設定
- I/O 操作
事件循環
當我們在 Node.js 中執行非同步任務時,事件循環是一切的核心。
得益於事件循環,Node.js 可以有效率地執行非阻塞 I/O 操作。它透過將耗時的任務委託給作業系統或工作執行緒來實現這一點。一旦任務完成,它們的回調就會以有組織的方式處理,確保順利執行而不阻塞主執行緒。
這就是 Node.js 能夠同時處理多個任務,同時仍然是單執行緒的神奇之處。
階段
事件循環中有六個階段,每個階段都有自己的佇列,其中保存特定類型的任務。
1.計時器階段
在此階段處理與計時器相關的回調,例如 setTimeout 和 setInterval。
Node js 檢查計時器佇列中是否有延遲已過期的回呼。
如果滿足計時器延遲,其回調將會加入此佇列中執行。
console.log('Start'); setTimeout(() => { console.log('Timer 1 executed after 1 second'); }, 1000); setTimeout(() => { console.log('Timer 2 executed after 0.5 seconds'); }, 500); let count = 0; const intervalId = setInterval(() => { console.log('Interval callback executed'); count++; if (count === 3) { clearInterval(intervalId); console.log('Interval cleared'); } }, 1000); console.log('End');
輸出:
Start End Timer 2 executed after 0.5 seconds Timer 1 executed after 1 second Interval callback executed Interval callback executed Interval callback executed Interval cleared
2.I/O回呼階段
此階段的目的是為已完成的 I/O(輸入/輸出)操作執行回調,例如讀取或寫入檔案、查詢資料庫、處理網路請求以及其他非同步 I/O 任務。
當 Node.js 中發生任何非同步 I/O 操作(例如使用 fs.readFile 讀取檔案)時,該操作將委託給作業系統或工作執行緒。這些 I/O 任務在主執行緒之外以非阻塞方式執行。任務完成後,會觸發回呼函數來處理結果。
I/O 回呼階段是操作完成後這些回呼排隊等待執行的階段。
const fs = require('fs'); console.log('Start'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file:', err); return; } console.log('File contents:', data); }); console.log('Middle'); setTimeout(() => { console.log('Simulated network request completed'); }, 0); console.log('End');
輸出
Start Middle End Simulated network request completed File contents: (contents of the example.txt file)
3.空閒階段
在此階段,不會執行任何使用者定義的工作,而是在此階段事件循環為下一階段做好準備。此階段僅進行內部調整。
4.投票階段
輪詢階段檢查是否有需要處理的待處理 I/O 事件(如網路活動或檔案系統事件)。它將立即執行與這些事件相關的回調。
如果沒有待處理的 I/O 事件,則輪詢階段可以進入阻塞狀態。
在這種阻塞狀態下,Node.js 將只是等待新的 I/O 事件到達。這種阻塞狀態使 Node.js 成為非阻塞:它會等待,直到新的 I/O 事件觸發回呼執行,同時保持主執行緒空閒以執行其他任務。
已完成的 I/O 操作(例如 fs.readFile、HTTP 請求或資料庫查詢)的任何回呼都會在此階段執行。這些 I/O 操作可能已在先前的階段(例如計時器階段或 I/O 回呼階段)啟動,現在已完成。
如果有使用 setTimeout 或 setInterval 設定的計時器,Node.js 將檢查是否有計時器已過期以及是否需要執行其關聯的回呼。如果計時器已過期,它們的回呼將移至回呼佇列,但直到下一階段(即計時器階段)才會處理它們。
const fs = require('fs'); const https = require('https'); console.log('Start'); fs.readFile('file1.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file1:', err); return; } console.log('File1 content:', data); }); fs.readFile('file2.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file2:', err); return; } console.log('File2 content:', data); }); https.get('https://jsonplaceholder.typicode.com/todos/1', (response) => { let data = ''; response.on('data', (chunk) => { data += chunk; }); response.on('end', () => { console.log('HTTP Response:', data); }); }); console.log('End');
輸出:
Start End File1 content: (contents of file1.txt) File2 content: (contents of file2.txt) HTTP Response: (JSON data from the HTTP request)
5.檢查相位
投票階段完成任務後。此階段主要處理 setImmediate 回呼的執行,這些回呼被安排在輪詢階段處理完 I/O 事件後立即執行。
當您想要在目前事件循環週期之後執行某個操作時,通常會使用 setImmediate 回調,例如確保系統不忙於處理 I/O 事件後執行某些任務。
檢查階段的優先權高於定時器階段(處理 setTimeout 和 setInterval)。這表示 setImmediate 回呼將始終在任何計時器之前執行,即使計時器已過期。
setImmediate 保證其回呼將在當前 I/O 週期之後、下一個計時器週期之前運行。當您想要確保在執行其他任務之前先完成 I/O 相關任務時,這一點非常重要。
console.log('Start'); setTimeout(() => { console.log('Timer 1 executed after 1 second'); }, 1000); setTimeout(() => { console.log('Timer 2 executed after 0.5 seconds'); }, 500); let count = 0; const intervalId = setInterval(() => { console.log('Interval callback executed'); count++; if (count === 3) { clearInterval(intervalId); console.log('Interval cleared'); } }, 1000); console.log('End');
輸出:
Start End Timer 2 executed after 0.5 seconds Timer 1 executed after 1 second Interval callback executed Interval callback executed Interval callback executed Interval cleared
6.結束階段
關閉回呼階段通常在應用程式需要在退出或關閉之前進行清理時執行。
此階段處理不再需要係統資源(例如網路套接字或檔案句柄)時需要執行的事件和任務。
如果沒有此階段,應用程式可能會留下開啟的檔案句柄、網路連接或其他資源,可能導致記憶體洩漏、資料損壞或其他問題。
const fs = require('fs'); console.log('Start'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file:', err); return; } console.log('File contents:', data); }); console.log('Middle'); setTimeout(() => { console.log('Simulated network request completed'); }, 0); console.log('End');
輸出:
Start Middle End Simulated network request completed File contents: (contents of the example.txt file)
Node JS 的事件循環中還有一個特殊的階段。
微任務隊列
process.nextTick() 並承諾在事件循環的特殊階段執行回呼。
process.nextTick() 安排回呼在目前操作完成後立即執行,但在事件循環繼續下一階段之前。
process.nextTick() 不是事件循環中任何階段的一部分。相反,它有自己的內部佇列,該佇列在當前執行的同步程式碼之後和進入事件循環中的任何階段之前立即執行。
它在目前操作之後但在 I/O、setTimeout 或事件循環中安排的其他任務之前執行。
Promise 的優先權低於 process.nextTick(),並且在所有 process.nextTick() 回呼之後處理。
const fs = require('fs'); const https = require('https'); console.log('Start'); fs.readFile('file1.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file1:', err); return; } console.log('File1 content:', data); }); fs.readFile('file2.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file2:', err); return; } console.log('File2 content:', data); }); https.get('https://jsonplaceholder.typicode.com/todos/1', (response) => { let data = ''; response.on('data', (chunk) => { data += chunk; }); response.on('end', () => { console.log('HTTP Response:', data); }); }); console.log('End');
輸出:
Start End File1 content: (contents of file1.txt) File2 content: (contents of file2.txt) HTTP Response: (JSON data from the HTTP request)
現在,您對事件循環的工作原理有了總體了解。
我給你一個問題,你可以在評論中給出答案。
const fs = require('fs'); console.log('Start'); fs.readFile('somefile.txt', 'utf8', (err, data) => { if (err) { console.error(err); return; } console.log('File content:', data); }); setImmediate(() => { console.log('Immediate callback executed'); }); setTimeout(() => { console.log('Timeout callback executed'); }, 0); console.log('End');
謝謝。
等待您的答覆。
以上是Node JS - 事件循環的詳細內容。更多資訊請關注PHP中文網其他相關文章!

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

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

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版
SublimeText3 Linux最新版

記事本++7.3.1
好用且免費的程式碼編輯器

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中