最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

V8是怎么執(zhí)行一段JavaScript代碼的?

2023-03-15 00:11 作者:文昌閣里學(xué)前端  | 我要投稿

V8 是一個由 Google 開發(fā)的開源 JavaScript 引擎,目前用在 Chrome 瀏覽器和 Node.js 中,其核心功能是執(zhí)行易于人類理解的 JavaScript 代碼。

那么 V8 又是怎么執(zhí)行 JavaScript 代碼的呢?

講述這塊內(nèi)容的過程可能會略微有點枯燥,但是懂得整個執(zhí)行過程更加利于你寫出更高執(zhí)行效率的代碼,懂得未來JavaScript發(fā)展趨勢,更能加深對JavaScript的理解。


V8 在執(zhí)行 JavaScript 代碼過程中其主要核心流程分為編譯和執(zhí)行兩步。首先需要將 JavaScript 代碼轉(zhuǎn)換為低級中間代碼或者機(jī)器能夠理解的機(jī)器代碼,然后再執(zhí)行轉(zhuǎn)換后的代碼并輸出執(zhí)行結(jié)果。

有同學(xué)可能會問,JavaScript源代碼不轉(zhuǎn)化成機(jī)器代碼難道就不能執(zhí)行了嗎?

答案是yes, 我們所編寫的JavaScript代碼依賴于宿主瀏覽器加載進(jìn)內(nèi)存,最后由CPU去執(zhí)行。而 CPU 只能識別二進(jìn)制的指令,但是對程序員來說,二進(jìn)制代碼閱讀、書寫難度超級大。 所以將實現(xiàn)各種功能的二進(jìn)制指令集轉(zhuǎn)化為人類可以識別和記憶的符號的匯編語言就出現(xiàn)了。


1000100111011000 機(jī)器指令 mov ax,bx 匯編指令

"1000100111011000" 這是二進(jìn)制指令,意思是將一個寄存器中的數(shù)據(jù)移動到另外一個寄存器中。 下面是匯編語言實現(xiàn)相同的功能,可以明顯感受到容易理解多了。


但是如果要匯編語言來實現(xiàn)一個功能,那么你需要為每種架構(gòu)的 CPU 編寫特定的匯編代碼,還需要了解和處理器架構(gòu)相關(guān)的硬件知識,比如寄存器、內(nèi)存、操作 CPU 等。

需要為每種架構(gòu)的CPU編寫特定的匯編代碼

因此我們需要一種屏蔽了計算機(jī)架構(gòu)細(xì)節(jié)的語言,能適應(yīng)多種不同 CPU 架構(gòu)的語言,能專心處理業(yè)務(wù)邏輯的語言,諸如 C、C++、Java、C#、Python、JavaScript 等,這些“高級語言”就應(yīng)運而生了。和匯編語言一樣,處理器也不能直接識別由高級語言所編寫的代碼,那怎么辦呢?


通常,要有兩種方式來執(zhí)行這些代碼。

第一種是解釋執(zhí)行,需要先將輸入的源代碼通過解析器編譯成中間代碼,之后直接使用解釋器解釋執(zhí)行中間代碼,然后直接輸出結(jié)果。具體流程如下圖所示:

第二種是編譯執(zhí)行。采用這種方式時,也需要先將源代碼轉(zhuǎn)換為中間代碼,然后我們的編譯器再將中間代碼編譯成機(jī)器代碼。通常編譯成的機(jī)器代碼是以二進(jìn)制文件形式存儲的,需要執(zhí)行這段程序的時候直接執(zhí)行二進(jìn)制文件就可以了。還可以使用虛擬機(jī)將編譯后的機(jī)器代碼保存在內(nèi)存中,然后直接執(zhí)行內(nèi)存中的二進(jìn)制代碼。


V8 在 2008 年剛推出的時候,它選擇的就是這種方式提供了一個快速編譯成機(jī)器碼的編譯器,雖然沒做太多優(yōu)化,但性能已經(jīng)是當(dāng)時其他 JavaScript 引擎的 10 倍了。對 JavaScript 編譯器來說,它最大的挑戰(zhàn)就在于,當(dāng)我們打開一個頁面的時候,源代碼的下載、解析(Parse)、編譯(Compile)和執(zhí)行,都要在很短的時間內(nèi)完成,否則就會影響到用戶的體驗。 而V8引擎的優(yōu)秀性能也帶動著chrome瀏覽器的迅速崛起。

目前V8的架構(gòu)跟最初發(fā)生了巨大的變化,它并沒有采用某種單一的技術(shù),而是混合編譯執(zhí)行和解釋執(zhí)行這兩種手段,我們把這種混合使用編譯器和解釋器的技術(shù)稱為 JIT(Just In Time)技術(shù)。

這是一種權(quán)衡策略,因為這兩種方法都各自有各自的優(yōu)缺點,解釋執(zhí)行的啟動速度快,但是執(zhí)行時的速度慢,而編譯執(zhí)行的啟動速度慢,但是執(zhí)行時的速度快。

我們先看上圖中的最左邊的部分,在 V8 啟動執(zhí)行 JavaScript 之前,它還需要準(zhǔn)備執(zhí)行 JavaScript 時所需要的一些基礎(chǔ)環(huán)境,這些基礎(chǔ)環(huán)境包括了“堆空間”“??臻g”“全局執(zhí)行上下文”“全局作用域”“消息循環(huán)系統(tǒng)”“內(nèi)置函數(shù)”等,這些內(nèi)容都是在執(zhí)行 JavaScript 過程中需要使用到的。

基礎(chǔ)環(huán)境準(zhǔn)備好之后,接下來就可以向 V8 提交要執(zhí)行的 JavaScript 代碼了。首先 V8 會接收到要執(zhí)行的 JavaScript 源代碼,不過這對 V8 來說只是一堆字符串,V8 并不能直接理解這段字符串的含義,它需要結(jié)構(gòu)化這段字符串。結(jié)構(gòu)化,是指信息經(jīng)過分析后可分解成多個互相關(guān)聯(lián)的組成部分。 (用白話講就是進(jìn)行詞法分析 ?語法分析)。

V8 源代碼的結(jié)構(gòu)化之后,就生成了抽象語法樹 (AST),我們稱為 AST,AST 是便于 V8 理解的結(jié)構(gòu)。


有了 AST 和作用域之后,接下來就可以生成字節(jié)碼了,字節(jié)碼是介于 AST 和機(jī)器代碼的中間代碼。但是與特定類型的機(jī)器代碼無關(guān),解釋器可以直接解釋執(zhí)行字節(jié)碼,或者通過編譯器將其編譯為二進(jìn)制的機(jī)器代碼再執(zhí)行。



生成了字節(jié)碼之后,解釋器就登場了,它會按照順序解釋執(zhí)行字節(jié)碼,并輸出執(zhí)行結(jié)果。相信你注意到了,在解釋器附近畫了個監(jiān)控機(jī)器人,這是一個監(jiān)控解釋器執(zhí)行狀態(tài)的模塊,在解釋執(zhí)行字節(jié)碼的過程中,如果發(fā)現(xiàn)了某一段代碼會被重復(fù)多次執(zhí)行,那么監(jiān)控機(jī)器人就會將這段代碼標(biāo)記為熱點代碼。


當(dāng)某段代碼被標(biāo)記為熱點代碼后,V8 就會將這段字節(jié)碼丟給優(yōu)化編譯器,優(yōu)化編譯器會在后臺將字節(jié)碼編譯為二進(jìn)制代碼,然后再對編譯后的二進(jìn)制代碼執(zhí)行優(yōu)化操作,如果再執(zhí)行到這段代碼時,那么 V8 會優(yōu)先選擇優(yōu)化之后的二進(jìn)制代碼由處理器直接執(zhí)行。這樣代碼的執(zhí)行速度就會大幅提升。


不過,和靜態(tài)語言不同的是,JavaScript 是一種非常靈活的動態(tài)語言,對象的結(jié)構(gòu)和屬性是可以在運行時任意修改的,而經(jīng)過優(yōu)化編譯器優(yōu)化過的代碼只能針對某種固定的結(jié)構(gòu),一旦在執(zhí)行過程中,對象的結(jié)構(gòu)被動態(tài)修改了,那么優(yōu)化之后的代碼勢必會變成無效的代碼,這時候優(yōu)化編譯器就需要執(zhí)行反優(yōu)化操作(也有叫去優(yōu)化操作),經(jīng)過反優(yōu)化的代碼,下次執(zhí)行時就會回退到解釋器解釋執(zhí)行。


所以你在復(fù)雜的項目中你要提升JavaScript的執(zhí)行效率跟性能,應(yīng)該減少反優(yōu)化。 總結(jié)成一句話:JavaScript引擎它喜歡你對象的結(jié)構(gòu)越穩(wěn)定越好,如果你把對象的結(jié)構(gòu)不停的在改變的話對它而言可優(yōu)化性就變低了。

那怎樣才能減少反優(yōu)化具體有哪些例子:

1:盡量在構(gòu)造函數(shù)中聲明對象屬性

2:盡量保持對象的穩(wěn)定性

3:多次調(diào)用某個函數(shù)時,盡量保持參數(shù)類型一致。

4:不要在函數(shù)中聲明類


V8是怎么執(zhí)行一段JavaScript代碼的?的評論 (共 條)

分享到微博請遵守國家法律
治多县| 大姚县| 泽州县| 固始县| 双牌县| 保康县| 维西| 伊金霍洛旗| 临武县| 凭祥市| 高要市| 桐梓县| 民权县| 高安市| 万州区| 泸水县| 红原县| 泰宁县| 衡阳县| 铁岭县| 建昌县| 军事| 常熟市| 西吉县| 聂拉木县| 五河县| 柳林县| 北票市| 铁力市| 盱眙县| 盘锦市| 兴山县| 铁力市| 雷波县| 六枝特区| 驻马店市| 山东省| 静海县| 昌江| 县级市| 偃师市|