一、邂逅node.js

什么是node.js

我們先看一下官方對(duì)Node.js的定義:
Node.js是一個(gè)基于V8 JavaScript引擎的JavaScript運(yùn)行時(shí)環(huán)境。
what?是不是看的一臉懵逼,什么是JavaScript運(yùn)行環(huán)境?為什么JavaScript需要特別的運(yùn)行環(huán)境呢?什么又是JavaScript引擎?什么是V8?
剛開(kāi)始就來(lái)一發(fā)五連問(wèn)。


01C183DD.jpg

不要驚慌,先來(lái)把這些概念搞清楚,再去看Node到底是什么。

JavaScript無(wú)處不在

Stack Overflow的創(chuàng)立者之一的 Jeff Atwood 在2007年提出了著名的 Atwood定律:
Any application that can be written in JavaScript, will eventually be written in JavaScript.
任何可以使用JavaScript來(lái)實(shí)現(xiàn)的應(yīng)用都最終都會(huì)使用JavaScript實(shí)現(xiàn)。

但是在發(fā)明之初,JavaScript的目的是用于在瀏覽器執(zhí)行簡(jiǎn)單的腳本任務(wù),對(duì)瀏覽器以及其中的DOM進(jìn)行各種操作,所以JavaScript的應(yīng)用場(chǎng)景非常受限。
但是隨著Node的出現(xiàn),Atwood定律已經(jīng)越來(lái)越多的被證實(shí)是正確的。
為了可以理解Node.js到底是如何幫助我們做到這一點(diǎn)的,我們必須了解JavaScript是如何被運(yùn)行的。

瀏覽器內(nèi)核

JavaScript代碼,在瀏覽器中是如何被執(zhí)行的?
不同的瀏覽器有不同的內(nèi)核組成:

  • Gecko:早期被Netscape和Mozilla Firefox瀏覽器使用;
  • Trident:微軟開(kāi)發(fā),被IE4~IE11瀏覽器使用,但是Edge瀏覽器已經(jīng)轉(zhuǎn)向Blink;
  • Webkit:蘋(píng)果基于KHTML開(kāi)發(fā)、開(kāi)源的,用于Safari,Google Chrome之前也在使用;
  • Blink:是Webkit的一個(gè)分支,Google開(kāi)發(fā),目前應(yīng)用于Google Chrome、Edge、Opera等;

事實(shí)上,我們經(jīng)常說(shuō)的瀏覽器內(nèi)核指的是瀏覽器的排版引擎
排版引擎(layout engine),也稱為瀏覽器引擎(browser engine)、頁(yè)面渲染引擎(rendering engine)
或樣版引擎
。

渲染引擎工作的過(guò)程

QQ截圖20201014224523.png

在這個(gè)執(zhí)行過(guò)程中,HTML解析的時(shí)候遇到了JavaScript標(biāo)簽,應(yīng)該怎么辦呢?
會(huì)停止解析HTML,而去加載和執(zhí)行JavaScript代碼。

為什么不直接異步去加載執(zhí)行JavaScript代碼,而要在這里停止掉呢?
是因?yàn)镴avaScript代碼可以操作我們的DOM,所以瀏覽器希望將HTML解析的DOM和JavaScript操作之后的DOM放到一起來(lái)生成最終的DOM樹(shù),而不是頻繁的去生成新的DOM樹(shù)。

那么,JavaScript代碼由誰(shuí)來(lái)執(zhí)行呢?
JavaScript引擎。

JavaScript引擎

為什么需要JavaScript引擎呢?

  • 事實(shí)上我們編寫(xiě)的JavaScript無(wú)論你交給瀏覽器或者Node執(zhí)行,最后都是需要被CPU執(zhí)行的;
  • 但是CPU只認(rèn)識(shí)自己的指令集,實(shí)際上是機(jī)器語(yǔ)言,才能被CPU所執(zhí)行;
  • 所以我們需要JavaScript引擎幫助我們將JavaScript代碼翻譯成CPU指令來(lái)執(zhí)行。

比較常見(jiàn)的JavaScript引擎有哪些呢?

  • SpiderMonkey:第一款JavaScript引擎,由Brendan Eich開(kāi)發(fā)(也就是JavaScript作者);
  • Chakra:微軟開(kāi)發(fā),用于IT瀏覽器;
  • JavaScriptCore:WebKit中的JavaScript引擎,Apple公司開(kāi)發(fā);
  • V8:Google開(kāi)發(fā)的強(qiáng)大JavaScript引擎,也幫助Chrome從眾多瀏覽器中脫穎而出;

WebKit內(nèi)核

這里我們先以WebKit為例,WebKit事實(shí)上由兩部分組成的:

  • WebCore:負(fù)責(zé)HTML解析、布局、渲染等等相關(guān)的工作
  • JavaScriptCore:解析、執(zhí)行JavaScript代碼

來(lái)看一下下面這張圖:


QQ截圖20201014225020.png
QQ截圖20201014225046.png

在小程序中編寫(xiě)的JavaScript代碼就是被JSCore執(zhí)行的。

V8引擎

來(lái)看一下官方對(duì)V8引擎的定義:

  • V8是用C ++編寫(xiě)的Google開(kāi)源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等。
  • 它實(shí)現(xiàn)ECMAScript和WebAssembly,并在Windows 7或更高版本,macOS 10.12+和使用x64,IA-32,
    ARM或MIPS處理器的Linux系統(tǒng)上運(yùn)行。
  • V8可以獨(dú)立運(yùn)行,也可以嵌入到任何C ++應(yīng)用程序中。

V8引擎的原理

QQ截圖20201014225247.png
  • Parse模塊會(huì)將JavaScript代碼轉(zhuǎn)換成AST(抽象語(yǔ)法樹(shù)),這是因?yàn)榻忉屍鞑⒉恢苯诱J(rèn)識(shí)JavaScript代碼
    如果函數(shù)沒(méi)有被調(diào)用,那么是不會(huì)被轉(zhuǎn)換成AST的
    Parse的V8官方文檔:https://v8.dev/blog/scanner
    Ignition是一個(gè)解釋器,會(huì)將AST轉(zhuǎn)換成ByteCode(字節(jié)碼)
    同時(shí)會(huì)收集TurboFan優(yōu)化所需要的信息(比如函數(shù)參數(shù)的類型信息,有了類型才能進(jìn)行真實(shí)的運(yùn)算);
    如果函數(shù)只調(diào)用一次,Ignition會(huì)執(zhí)行解釋執(zhí)行ByteCode;
    gnition的V8官方文檔:https://v8.dev/blog/ignition-interpreter
  • TurboFan是一個(gè)編譯器,可以將字節(jié)碼編譯為CPU可以直接執(zhí)行的機(jī)器碼;
    如果一個(gè)函數(shù)被多次調(diào)用,那么就會(huì)被標(biāo)記為熱點(diǎn)函數(shù),那么就會(huì)經(jīng)過(guò)TurboFan轉(zhuǎn)換成優(yōu)化的機(jī)器碼,提高代碼的執(zhí)行性能;
    但是,機(jī)器碼實(shí)際上也會(huì)被還原為ByteCode,這是因?yàn)槿绻罄m(xù)執(zhí)行函數(shù)的過(guò)程中,類型發(fā)生了變化(比如sum函數(shù)原來(lái)執(zhí)行的是number類型,后
    TurboFan的V8官方文檔:https://v8.dev/blog/turbofan-jit

回顧:Node.js是什么

回顧:官方對(duì)Node.js的定義:
Node.js是一個(gè)基于V8 JavaScript引擎的JavaScript運(yùn)行時(shí)環(huán)境。
也就是說(shuō)Node.js基于V8引擎來(lái)執(zhí)行JavaScript的代碼,但是不僅僅只有V8引擎。

  • 前面我們知道V8可以嵌入到任何C ++應(yīng)用程序中,無(wú)論是Chrome還是Node.js,事實(shí)上都是嵌入了V8引擎
    來(lái)執(zhí)行JavaScript代碼;
  • 但是在Chrome瀏覽器中,還需要解析、渲染HTML、CSS等相關(guān)渲染引擎,另外還需要提供支持瀏覽器操作的API、瀏覽器自己的事件循環(huán)等;
  • 另外,在Node.js中我們也需要進(jìn)行一些額外的操作,比如文件系統(tǒng)讀/寫(xiě)、網(wǎng)絡(luò)IO、加密、壓縮解壓文件等
    操作

瀏覽器和Node.js架構(gòu)區(qū)別

QQ截圖20201014225718.png

給node程序傳遞參數(shù)

node index.js env=development coderwhy

獲?。?br> process.argv

Node的輸出

  • console.log
  • console.clear
    清空打印信息,也就是說(shuō)前面有console.log的話會(huì)被清空
  • console.trace
    向控制臺(tái)輸出一個(gè)堆棧跟蹤。

常見(jiàn)的全局對(duì)象

  • process
  • console
  • 定時(shí)器函數(shù)
    • setTimeout(callback, delay[, ...args]):callback在delay毫秒后執(zhí)行一次;
    • setInterval(callback, delay[, ...args]):callback每delay毫秒重復(fù)執(zhí)行一次;
    • setImmediate(callback[, ...args]):callbackI / O事件后的回調(diào)的“立即”執(zhí)行;
    • process.nextTick(callback[, ...args]):添加到下一次tick隊(duì)列中;

特殊的全局對(duì)象

這些全局對(duì)象可以在模塊中任意使用,但是在命令行交互中是不可以使用的;包括:__dirname、__filename、exports、module、require()。

  • __dirname:獲取當(dāng)前文件所在的路徑:不包括后面的文件名
  • __filename:獲取當(dāng)前文件所在的路徑和文件名稱:包括后面的文件名稱

global對(duì)象

global是一個(gè)全局對(duì)象,process、console、setTimeout等都有被放到global中。

global和window的區(qū)別

  • 在瀏覽器中,全局變量都是在window上的,比如有document、setInterval、setTimeout、alert、console等等
  • 在Node中,我們也有一個(gè)global屬性,并且看起來(lái)它里面有很多其他對(duì)象。
  • 但是在瀏覽器中執(zhí)行的JavaScript代碼,如果我們?cè)陧敿?jí)范圍內(nèi)通過(guò)var定義的一個(gè)屬性,默認(rèn)會(huì)被添加到window
    對(duì)象上
  • 但是在node中,我們通過(guò)var定義一個(gè)變量,它只是在當(dāng)前模塊中有一個(gè)變量,不會(huì)放到全局中
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容