nodejs執(zhí)行javaScript原理超詳細講解
前言
Node.js 執(zhí)行 JavaScript 的過程可以分解為一個高效、事件驅(qū)動的運行模型。它與瀏覽器中的 JavaScript 引擎有相似的核心,但有不同的全局環(huán)境和能力。
簡單來說,Node.js 使用 V8 引擎 來執(zhí)行 JavaScript 代碼,并通過 事件循環(huán)(Event Loop) 來處理異步操作。
下面我們來詳細拆解這個過程。
核心架構(gòu):不只是 V8
Node.js 的運行時環(huán)境主要由以下幾個部分組成:
V8 引擎:來自 Google,負責編譯和執(zhí)行 JavaScript 代碼。它將 JS 代碼轉(zhuǎn)換成更快的機器碼,而不是一行行地解釋執(zhí)行。
LibUV:一個用 C 編寫的庫,它提供了 事件循環(huán)(Event Loop)、線程池 和異步 I/O 操作(如文件系統(tǒng)、網(wǎng)絡操作)的能力。這是 Node.js 實現(xiàn)非阻塞 I/O 的關鍵。
其他底層庫:如
http-parser、c-ares、OpenSSL等,分別用于處理 HTTP、DNS 和加密等。
執(zhí)行流程詳解
當你運行 node app.js 時,會發(fā)生以下步驟:
第 1 步:初始化環(huán)境
Node.js 啟動,初始化 V8 引擎、LibUV 等組件。
創(chuàng)建事件循環(huán)。
設置全局對象(如
global、process)、模塊加載系統(tǒng)等。
第 2 步:加載并執(zhí)行你的代碼
Node.js 讀取你的
app.js文件。V8 引擎開始處理這段代碼。這個過程包括:
解析:將 JS 代碼轉(zhuǎn)換成抽象語法樹(AST)。
編譯:V8 的即時編譯(JIT)引擎會將 AST 編譯成高效的機器碼。
執(zhí)行:CPU 執(zhí)行生成的機器碼。
第 3 步:處理同步與異步操作(關鍵階段)
這是 Node.js 并發(fā)模型的核心。
同步任務:會立即在主線程上按順序執(zhí)行,這與在瀏覽器中一樣。
異步任務(如
fs.readFile、setTimeout、http.request):當遇到異步操作時,Node.js 會立即返回,繼續(xù)執(zhí)行后面的同步代碼,不會“阻塞”在這里。
同時,它會將這個異步操作及其回調(diào)函數(shù) 交給 LibUV 去處理。
第 4 步:LibUV 與事件循環(huán)的工作
LibUV 通過事件循環(huán)來協(xié)調(diào)這些異步操作。事件循環(huán)是一個無限循環(huán),它不斷地檢查是否有待處理的事件。其簡化模型如下:
┌───────────────────────────┐
┌─>│ 定時器 │ (執(zhí)行到點的 setTimeout、setInterval 回調(diào))
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │ (執(zhí)行大部分系統(tǒng)操作的回調(diào),如 TCP 錯誤)
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │ (內(nèi)部使用)
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ 輪詢 poll │ ?─── 最重要的階段
│ └─────────────┬─────────────┘ - 檢索新的 I/O 事件
│ ┌─────────────┴─────────────┐ - 執(zhí)行與 I/O 相關的回調(diào)
│ │ 檢查 check │ (執(zhí)行 setImmediate 的回調(diào))
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ 關閉事件回調(diào) close │ (執(zhí)行關閉事件的回調(diào),如 socket.on('close', ...))
└───────────────────────────┘
不同類型的異步任務被放入不同的隊列:
定時器:
setTimeout和setInterval的回調(diào)。I/O 操作 & 輪詢:文件讀寫、網(wǎng)絡請求等。這是最繁忙的階段。
檢查階段:
setImmediate的回調(diào)。微任務:
Promise.then()、process.nextTick()。注意:微任務在每個階段之間都會優(yōu)先清空,這意味著process.nextTick和Promise的回調(diào)總是比上面提到的其他異步回調(diào)執(zhí)行得更早。
第 5 步:執(zhí)行回調(diào)
當異步操作完成時(例如,文件讀取完畢或定時器超時),LibUV 會將對應的回調(diào)函數(shù)放入相應的隊列中。事件循環(huán)在到達對應階段時,會從隊列中取出回調(diào)函數(shù),送到 V8 引擎中去執(zhí)行。
一個簡單的例子
// 同步代碼
console.log('Script start'); // 1. 立即執(zhí)行
// 異步代碼 - 定時器
setTimeout(() => {
console.log('setTimeout'); // 4. 在定時器階段執(zhí)行
}, 0);
// 異步代碼 - Promise (微任務)
Promise.resolve().then(() => {
console.log('Promise'); // 3. 在同步代碼執(zhí)行后,事件循環(huán)下一個階段前執(zhí)行
});
// 同步代碼
console.log('Script end'); // 2. 立即執(zhí)行輸出順序為:
Script start
Script end
Promise
setTimeout
總結(jié):Node.js 如何執(zhí)行 JS
核心引擎:使用 V8 來編譯和執(zhí) JavaScript 代碼。
非阻塞 I/O:通過 LibUV 來處理所有異步操作,使其不阻塞主線程。
事件驅(qū)動:事件循環(huán) 是中樞,它不斷地輪詢,檢查已完成的事件,然后安排對應的回調(diào)函數(shù)執(zhí)行。
單線程但高效:你的 JavaScript 代碼(回調(diào))是在單個主線程上運行的,但所有的 I/O 操作都是通過 LibUV 在底層多線程或系統(tǒng)內(nèi)核的幫助下異步完成的。這使得 Node.js 可以用一個線程處理成千上萬的并發(fā)連接。
這種模型非常適合 I/O 密集型的應用(如 Web 服務器、數(shù)據(jù)庫工具),因為大部分時間都在等待 I/O,而不是進行大量計算。
到此這篇關于nodejs執(zhí)行javaScript原理的文章就介紹到這了,更多相關nodejs執(zhí)行JS原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用Make構(gòu)建Node.js網(wǎng)站項目
這篇文章介紹了使用Make構(gòu)建Node.js網(wǎng)站項目的方法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-01-01
在 Node.js 中使用 async 函數(shù)的方法
利用 async 函數(shù),你可以把基于 Promise 的異步代碼寫得就像同步代碼一樣。一旦你使用 async 關鍵字來定義了一個函數(shù),那你就可以在這個函數(shù)內(nèi)使用 await 關鍵字。下面通過本文給大家分享Node.js 中使用 async 函數(shù)的方法,一起看看吧2017-11-11
使用Node.js和PostgreSQL構(gòu)建數(shù)據(jù)庫應用
PostgreSQL是一個功能強大的開源關系型數(shù)據(jù)庫,而Node.js是構(gòu)建高效網(wǎng)絡應用的理想平臺,結(jié)合這兩個技術,我們可以創(chuàng)建出色的數(shù)據(jù)驅(qū)動應用,本文就來介紹一下使用Node.js中的`pg`庫與PostgreSQL數(shù)據(jù)庫進行交互,感興趣的可以了解一下2025-09-09
nodejs發(fā)布靜態(tài)https服務器步驟指南
這篇文章主要為大家介紹了nodejs發(fā)布靜態(tài)https服務器的步驟指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2024-02-02
vscode+nodejs+express搭建一個簡單網(wǎng)站(附詳細圖文教程)
作為前端開發(fā),Nodejs已經(jīng)成了很多公司對我們這一崗位的硬性要求,而Express框架則是其中知名度最高、也是最受歡迎的Nodejs開發(fā)框架,這篇文章主要介紹了vscode+nodejs+express搭建一個簡單網(wǎng)站的相關資料,需要的朋友可以參考下2026-01-01

