日韩国产精品99成人不卡在线无毒|狠狠躁夜夜爽一级二级精品|亚洲日日噜噜孕妇中文字幕|日韩久草中文三级片

新聞動態(tài)

JavaScript 運行原理

常見問題 發(fā)布者:cya 2019-12-12 08:35 訪問量:375

譯文:梁天培

鏈接:https://juejin.im/post/5d84ae08e51d4561a705bbde

原文鏈接:https://blog.bitsrc.io/javascript-under-the-hood-632ccae06b27

最初,JavaScript 只能在 Web 瀏覽器中運行,但是隨著 Node 的出現(xiàn),現(xiàn)在 JavaScript 也可以在服務(wù)端運行。雖然我們可能知道應(yīng)該在何時何地去使用它, 但是我們真的了解這些腳本執(zhí)行的背后發(fā)生了什么嗎?

如果您覺得自己對 JavaScript 引擎有了一些了解的話,可以先給自己鼓個掌,但不要急著關(guān)掉本文,我相信閱讀完成后您仍然可以從中學(xué)到一些東西。

JavaScript 是一門高級語言,但是最終計算機(jī)能理解只有1和0。那么我們編寫的代碼是如何被計算機(jī)理解的呢?掌握所學(xué)編程語言的基礎(chǔ)知識將讓您能編寫出更好的代碼。在本文中,我們僅探討一個問題:JavaScript 是如何工作的?

JavaScript 引擎

這是本文將要探索的主要內(nèi)容,它負(fù)責(zé)使計算機(jī)理解我們編寫的 JS 代碼。JavaScript 引擎是一種用于將我們的代碼轉(zhuǎn)換為機(jī)器可讀語言的引擎。如果沒有 JavaScript 引擎,您編寫的代碼對計算機(jī)來說簡直是一堆“胡言亂語”。不僅僅是 JavaScript ,其他所有編程語言都需要一個類似的引擎,來將這些“胡言亂語”轉(zhuǎn)換成對計算機(jī)有意義的語言。

目前有多種 JavaScript 引擎在可供使用。您可以在 Wikipedia 上查閱所有可用的 JavaScript 引擎。它們也被稱為 ECMAScript 引擎,這樣叫的具體原因會在下文中提及。下面是一些我們?nèi)粘?赡軙玫降?JavaScript 引擎:

  • Chakra, Microsoft IE/Edge

  • SpiderMonkey, FireFox

  • V8, Chrome

除此之外的其它引擎,可以自行搜索了解。接下來,我們將深入研究這些引擎,以了解它們是如何翻譯 JavaScript 文件的。

JavaScript 引擎的內(nèi)里

我們已經(jīng)知道了引擎是必須的,由此可能不禁會想:

是誰發(fā)明了 JavaScript 引擎?

答案是,任何人都可以。它只是分析我們的代碼并將其翻譯的另一種語言的工具。V8 是最受歡迎的 JavaScript 引擎之一,也是 Chrome 和 NodeJS 使用的引擎。它是用 C++(一種底層語言)編寫的。但是如果每個人都創(chuàng)造一個引擎,那場面就不是可控范圍內(nèi)的了。

因此,為了給這些引擎確立一個規(guī)范,ECMA 的標(biāo)準(zhǔn)誕生了,該標(biāo)準(zhǔn)主要提供如何編寫引擎和 JavaScript 所有功能的規(guī)范。這就是新功能能在 ECMAScript 6、7、8 上實現(xiàn)的原因。同時,引擎也進(jìn)行了更新以支持這些新功能。于是,我們便可以在開發(fā)過程中檢查了瀏覽器中 JS 高級功能的可用性。

下面我們對 V8 引擎進(jìn)行進(jìn)一步的探索,因為基本概念在所有引擎中是一致的。

JavaScript V8 Engine

上圖就是 JS Engine 內(nèi)部的工作流程。我們輸入的代碼將通過以下階段,

  • Parser

  • AST

  • Interpreter 生成 ByteCode

  • Profiler

  • Compiler 生成優(yōu)化后的代碼

別被上面的流程給唬住了,在幾分鐘后您將了解它們是協(xié)同運作的。

在進(jìn)一步深入這些階段之前,您需要先了解 Interpreter 和 Compiler 的區(qū)別。

Interpreter VS Compiler

通常,將代碼轉(zhuǎn)換成機(jī)器可讀語言的方法有兩種。我們將要討論的概念不僅適用于 JavaScript ,而且適用于大多數(shù)編程語言,例如 Python,Java 等。

  • Interpreter 逐行讀取代碼并立即執(zhí)行。

  • Compiler 讀取您的整個代碼,進(jìn)行一些優(yōu)化,然后生成優(yōu)化后的代碼。

讓我們來看下面這個例子。

function add(a, b{
    return a+b
}
for(let i = 0; i < 1000; i++) {
    add(1 + 1)
}

上面的示例循環(huán)調(diào)用了 add 函數(shù)1000次,該函數(shù)將兩個數(shù)字相加并返回總和。

Interpreter 接收上面的代碼后,它將逐行讀取并立即執(zhí)行代碼,直到循環(huán)結(jié)束。它的工作僅僅是實時地將代碼轉(zhuǎn)換為我們的計算機(jī)可以理解的內(nèi)容。

如果這段代碼接受者是 Compiler,它會先完整地讀取整個程序,對我們要執(zhí)行的代碼進(jìn)行分析,并生成電腦可以讀懂的機(jī)器語言。過程如同獲取 X(我們的JS文件)并生成 Y(機(jī)器語言)一樣。如果我們使用 Interpreter 執(zhí)行 Y,則會獲得與執(zhí)行 X 相同的結(jié)果。

從上圖中可以看出,ByteCode 只是中間碼,計算機(jī)仍需要對其進(jìn)行翻譯才能執(zhí)行。但是 Interpreter 和 Compiler 都將源代碼轉(zhuǎn)換為機(jī)器語言,它們唯一的區(qū)別在于轉(zhuǎn)換的過程不盡相同。

  • Interpreter 逐行將源代碼轉(zhuǎn)換為等效的機(jī)器代碼。

  • Compiler 在一開始就將所有源代碼轉(zhuǎn)換為機(jī)器代碼。

如果你想了解更多它們之前的區(qū)別,推薦閱讀這篇文章。

當(dāng)您閱讀完上面的推薦文章后,您可能已經(jīng)了解到 Babel 實際上是一個 JS Compiler ,它可以接收您編寫的新版本 JS 代碼并向下編譯為與瀏覽器兼容的 JS 代碼(舊版本的 JS 代碼)。

Interpreter 和 Compiler 的優(yōu)缺點

Interpreter 的優(yōu)點是無需等待編譯即可立即執(zhí)行代碼。這對在瀏覽器中運行 JS 提供了極大的便利,因為所有用戶都不想浪費時間在等待代碼編譯這件事上。但是,當(dāng)有大量的 JS 代碼需要執(zhí)行時會運行地比較慢。還記得上面例子中的那一小段代碼嗎?代碼中執(zhí)行了1000次函數(shù)調(diào)用。函數(shù) add 被調(diào)用了1000次,但他的輸出保持不變。但是 Interpreter 還是逐行執(zhí)行,會顯得比較慢。

在同樣的情況下,Compiler 可以通過用2代替循環(huán)(因為 add 函數(shù)每次都是執(zhí)行1 + 1)來進(jìn)行一些優(yōu)化。Compiler 最終給出的優(yōu)化代碼可以在更短的時間內(nèi)執(zhí)行完成。

綜上所述,Interpreter 可以立即開始執(zhí)行代碼,但不會進(jìn)行優(yōu)化。Compiler 雖然需要花費一些時間來編譯代碼,但是會生成對執(zhí)行時更優(yōu)的代碼。

好的,Interpreter 和 Compiler 必要知識我們已經(jīng)了解了。現(xiàn)在讓我們回到主題——JS 引擎。

因此,考慮到編譯器和解釋器的優(yōu)缺點,如果我們同時利用兩者的優(yōu)點,該怎么辦?這就是 JIT(Just In Time) Compiler 的用武之地。它是 Interpreter 和 Compiler 的結(jié)合,現(xiàn)在大多數(shù)瀏覽器都在更快,更高效地實現(xiàn)此功能。同時 V8 引擎也使用此功能。

JavaScript V8 Engine

在這個過程中,

Parser 是一種通過各種 JavaScript 關(guān)鍵字來識別,分析和分類程序各個部分的解析器。它可以區(qū)分代碼是一個方法還是一個變量。

然后,AST(抽象語法樹) 基于 Parser 的分類構(gòu)造樹狀結(jié)構(gòu)。您可以使用 AST Explorer 查看該樹的結(jié)構(gòu)。

隨后將 AST 提供給 Interpreter 生成 ByteCode。如上文所述,ByteCode 不是最底層的代碼,但可以被執(zhí)行。在此階段,瀏覽器借助 V8 引擎執(zhí)行 ByteCode 進(jìn)行工作,因此用戶無需等待。

同時,Profiler 將查找可以被優(yōu)化的代碼,然后將它們傳遞給 Compiler。Compiler 生成優(yōu)化代碼的同時,瀏覽器暫時用 ByteCode 執(zhí)行操作。并且,一旦 Compiler 生成了優(yōu)化代碼,優(yōu)化代碼則將完全替換掉臨時的 ByteCode。

通過這種方式,我們可以充分利用 Interpreter 和 Compiler 的優(yōu)點。Interpreter 執(zhí)行代碼的同時,Profiler 尋找可以被優(yōu)化的代碼,Compiler 則創(chuàng)建優(yōu)化的代碼。然后,將 ByteCode 碼替換為優(yōu)化后的較為底層的代碼,例如機(jī)器代碼。

這僅意味著性能將在逐漸提高,同時不會有阻塞執(zhí)行的時間。

關(guān)于 ByteCode

作為機(jī)器代碼,ByteCode 不能被所有計算機(jī)理解及執(zhí)行。它仍然需要像虛擬機(jī)或像 Javascript V8 引擎這樣的中間件才能將其轉(zhuǎn)換為機(jī)器可讀的語言。這就是為什么我們的瀏覽器可以在上述5個階段中借助 JavaScript 引擎在 Interpreter 中執(zhí)行 ByteCode 的原因。

所以您可以會有另一個問題,

JavaScript 是一門解釋型語言嗎?

JavaScript 是但不完全是一門解釋型語言。Brendan Eich 最初是在 JavaScript 的早期階段創(chuàng)建 JavaScript 引擎 “ SpiderMonkey” 的。該引擎有一個 Interpreter 來告訴瀏覽器該怎么執(zhí)行代碼。但是現(xiàn)在我們的引擎不僅包括了 Interpreter,還有 Compiler。我們的代碼不僅可以被轉(zhuǎn)換成 ByteCode,還可以被編譯輸出優(yōu)化后的代碼。因此,從技術(shù)上講,這完全取決于引擎是如何實現(xiàn)的。

JavaScript 引擎的整體工作原理就是這樣。相信您無需學(xué)習(xí) JavaScript 也可以理解。當(dāng)然,您甚至可以在不知道 JavaScript 如何工作的情況下編寫代碼。但是,如果我們了解一些幕后的知識,或許能讓我們編寫出更好的代碼。



關(guān)鍵字: JavaScript 運行原理 開封網(wǎng)站建設(shè)

文章連接: http://m.hsjyfc.com.cn/cjwt/643.html

版權(quán)聲明:文章由 晨展科技 整理收集,來源于互聯(lián)網(wǎng)或者用戶投稿,如有侵權(quán),請聯(lián)系我們,我們會立即刪除。如轉(zhuǎn)載請保留