瞭解JavaScript引擎
JavaScript 是一門高階語言,但是最終計算機能理解只有1和0。 那麼我們編寫的程式碼是如何被計算機理解的呢? 掌握所學程式語言的基礎知識將讓您能編寫出更好的程式碼。 在本文中,我們僅探討一個問題:JavaScript 是如何工作的。 |
最初,JavaScript 只能在 Web 瀏覽器中執行,但是隨著 Node 的出現,現在 JavaScript 也可以在服務端執行。雖然我們可能知道應該在何時何地去使用它, 但是我們真的瞭解這些 執行的背後發生了什麼嗎?
如果您覺得自己對 JavaScript 引擎有了一些瞭解的話,可以先給自己鼓個掌,但不要急著關掉本文,我相信閱讀完成後您仍然可以從中學到一些東西。
JavaScript 是一門高階語言,但是最終計算機能理解只有1和0。 那麼我們編寫的程式碼是如何被計算機理解的呢? 掌握所學程式語言的基礎知識將讓您能編寫出更好的程式碼。 在本文中,我們僅探討一個問題:JavaScript 是如何工作的?
下面讓我們進入正題~
這是本文將要探索的主要內容,它負責使計算機理解我們編寫的 JS 程式碼。JavaScript 引擎是一種用於將我們的程式碼轉換為機器可讀語言的引擎。如果沒有 JavaScript 引擎,您編寫的程式碼對計算機來說簡直是一堆“胡言亂語”。不僅僅是 JavaScript ,其他所有程式語言都需要一個類似的引擎,來將這些“胡言亂語”轉換成對計算機有意義的語言。
目前有多種 JavaScript 引擎在可供使用。您可以在 Wikipedia 上查閱所有可用的 JavaScript 引擎。它們也被稱為 ECMAScript 引擎,這樣叫的具體原因會在下文中提及。 下面是一些我們日常可能會用到的 JavaScript 引擎:
- Chakra, Microsoft IE/Edge
- SpiderMonkey, FireFox
- V8, Chrome
除此之外的其它引擎,可以自行搜尋瞭解。接下來,我們將深入研究這些引擎,以瞭解它們是如何翻譯 JavaScript 檔案的。
我們已經知道了引擎是必須的,由此可能不禁會想:
是誰發明了 JavaScript 引擎?
答案是,任何人都可以。它只是分析我們的程式碼並將其翻譯的另一種語言的工具。V8 是最受歡迎的 JavaScript 引擎之一,也是 Chrome 和 NodeJS 使用的引擎。它是用 C++(一種底層語言)編寫的。但是如果每個人都創造一個引擎,那場面就不是可控範圍內的了。
因此,為了給這些引擎確立一個規範,ECMA 的標準誕生了,該標準主要提供如何編寫引擎和 JavaScript 所有功能的規範。這就是新功能能在 ECMAScript 6、7、8 上實現的原因。同時,引擎也進行了更新以支援這些新功能。 於是,我們便可以在開發過程中檢查了瀏覽器中 JS 高階功能的可用性。
下面我們對 V8 引擎進行進一步的探索,因為基本概念在所有引擎中是一致的。
上圖就是 JS Engine 內部的工作流程。我們輸入的程式碼將透過以下階段:
- Parser
- AST
- Interpreter 生成 ByteCode
- Profiler
- Compiler 生成最佳化後的程式碼
別被上面的流程給唬住了,在幾分鐘後您將瞭解它們是協同運作的。
在進一步深入這些階段之前,您需要先了解 Interpreter 和 Compiler 的區別。
通常,將程式碼轉換成機器可讀語言的方法有兩種。 我們將要討論的概念不僅適用於 JavaScript ,而且適用於大多數程式語言,例如 Python,Java 等。
- Interpreter 逐行讀取程式碼並立即執行。
- Compiler 讀取您的整個程式碼,進行一些最佳化,然後生成最佳化後的程式碼。
讓我們來看下面這個例子。
function add(a, b) { return a+b } for(let i = 0; i < 1000; i++) { add(1 + 1) }
上面的示例迴圈呼叫了 add 函式1000次,該函式將兩個數字相加並返回總和。
- 1、Interpreter 接收上面的程式碼後,它將逐行讀取並立即執行程式碼,直到迴圈結束。 它的工作僅僅是實時地將程式碼轉換為我們的計算機可以理解的內容。
- 2、如果這段程式碼接受者是 Compiler,它會先完整地讀取整個程式,對我們要執行的程式碼進行分析,並生成電腦可以讀懂的機器語言。過程如同獲取 X(我們的JS檔案)並生成 Y(機器語言)一樣。如果我們使用 Interpreter 執行 Y,則會獲得與執行 X 相同的結果。
從上圖中可以看出,ByteCode 只是中間碼,計算機仍需要對其進行翻譯才能執行。 但是 Interpreter 和 Compiler 都將原始碼轉換為機器語言,它們唯一的區別在於轉換的過程不盡相同。
- Interpreter 逐行將原始碼轉換為等效的機器程式碼。
- Compiler 在一開始就將所有原始碼轉換為機器程式碼。
當您閱讀完上面的推薦文章後,您可能已經瞭解到 Babel 實際上是一個 JS Compiler ,它可以接收您編寫的新版本 JS 程式碼並向下編譯為與瀏覽器相容的 JS 程式碼(舊版本的 JS 程式碼)。
- 1、Interpreter 的優點是無需等待編譯即可立即執行程式碼。這對在瀏覽器中執行 JS 提供了極大的便利,因為所有使用者都不想浪費時間在等待程式碼編譯這件事上。但是,當有大量的 JS 程式碼需要執行時會執行地比較慢。還記得上面例子中的那一小段程式碼嗎?程式碼中執行了1000次函式呼叫。函式 add 被呼叫了1000次,但他的輸出保持不變。但是 Interpreter 還是逐行執行,會顯得比較慢。
- 2、在同樣的情況下,Compiler 可以透過用2代替迴圈(因為 add 函式每次都是執行1 + 1)來進行一些最佳化。Compiler 最終給出的最佳化程式碼可以在更短的時間內執行完成。
- 綜上所述,Interpreter 可以立即開始執行程式碼,但不會進行最佳化。 Compiler 雖然需要花費一些時間來編譯程式碼,但是會生成對執行時更優的程式碼。
好的,Interpreter 和 Compiler 必要知識我們已經瞭解了。現在讓我們回到主題——JS 引擎。
因此,考慮到編譯器和直譯器的優缺點,如果我們同時利用兩者的優點,該怎麼辦? 這就是 JIT(Just In Time) Compiler 的用武之地。它是 Interpreter 和 Compiler 的結合,現在大多數瀏覽器都在更快,更高效地實現此功能。同時 V8 引擎也使用此功能。
在這個過程中,
- 1、Parser 是一種透過各種 JavaScript 關鍵字來識別,分析和分類程式各個部分的解析器。它可以區分程式碼是一個方法還是一個變數。
- 2、然後,AST(抽象語法樹) 基於 Parser 的分類構造樹狀結構。您可以使用 AST Explorer 檢視該樹的結構。
- 3、隨後將 AST 提供給 Interpreter 生成 ByteCode。如上文所述,ByteCode 不是最底層的程式碼,但可以被執行。在此階段,瀏覽器藉助 V8 引擎執行 ByteCode 進行工作,因此使用者無需等待。
- 4、同時,Profiler 將查詢可以被最佳化的程式碼,然後將它們傳遞給 Compiler。Compiler 生成最佳化程式碼的同時,瀏覽器暫時用 ByteCode 執行操作。並且,一旦 Compiler 生成了最佳化程式碼,最佳化程式碼則將完全替換掉臨時的 ByteCode。
- 5、 透過這種方式,我們可以充分利用 Interpreter 和 Compiler 的優點。Interpreter 執行程式碼的同時,Profiler 尋找可以被最佳化的程式碼,Compiler 則建立最佳化的程式碼。然後,將 ByteCode 碼替換為最佳化後的較為底層的程式碼,例如機器程式碼。
這僅意味著效能將在逐漸提高,同時不會有阻塞執行的時間。
作為機器程式碼,ByteCode 不能被所有計算機理解及執行。它仍然需要像虛擬機器或像 Javascript V8 引擎這樣的中介軟體才能將其轉換為機器可讀的語言。 這就是為什麼我們的瀏覽器可以在上述5個階段中藉助 JavaScript 引擎在 Interpreter 中執行 ByteCode 的原因。
所以您可以會有另一個問題,
JavaScript 是但不完全是一門解釋型語言。Brendan Eich 最初是在 JavaScript 的早期階段建立 JavaScript 引擎 “ SpiderMonkey” 的。該引擎有一個 Interpreter 來告訴瀏覽器該怎麼執行程式碼。 但是現在我們的引擎不僅包括了 Interpreter,還有 Compiler。 我們的程式碼不僅可以被轉換成 ByteCode,還可以被編譯輸出最佳化後的程式碼。 因此,從技術上講,這完全取決於引擎是如何實現的。
JavaScript 引擎的整體工作原理就是這樣。相信您無需學習 JavaScript 也可以理解。 當然,您甚至可以在不知道 JavaScript 如何工作的情況下編寫程式碼。 但是,如果我們瞭解一些幕後的知識,或許能讓我們編寫出更好的程式碼。
原文地址:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2661736/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JavaScript——深入瞭解thisJavaScript
- Express基礎瞭解—模板引擎Express
- 你真的瞭解Innodb儲存引擎?儲存引擎
- 深入瞭解React新引擎:ReactFiberReact
- 瞭解 JavaScript 的遞迴JavaScript遞迴
- 圖解搞懂JavaScript引擎Event Loop圖解JavaScriptOOP
- JavaScript 你真的瞭解this指向嗎JavaScript
- 深入瞭解JavaScript中的物件JavaScript物件
- 瞭解一下搜尋引擎的結構
- 全面瞭解 Javascript Prototype Chain 原型鏈JavaScriptAI原型
- 深入瞭解 JavaScript 中的 for 迴圈JavaScript
- 瞭解 JavaScript 中的內建物件JavaScript物件
- javascript遊戲引擎JavaScript遊戲引擎
- [譯] 通過 Lighthouse 瞭解 JavaScript 效能JavaScript
- 瞭解JavaScript中的型別轉換JavaScript型別
- 深入瞭解 JavaScript 記憶體洩漏JavaScript記憶體
- 簡單瞭解JavaScript垃圾回收機制JavaScript
- javascript引擎工作原理JavaScript
- JavaScript 模板引擎概述JavaScript
- 瞭解一下JavaScript繼承的方法JavaScript繼承
- 大佬,JavaScript 柯里化,瞭解一下?JavaScript
- 我所瞭解的JavaScript糟粕和雞肋JavaScript
- [譯] 漫畫圖解 JavaScript 引擎: let jsCartoons = ‘Awesome’;圖解JavaScriptJS
- 瀏覽器引擎、渲染引擎與JavaScript引擎的區別瀏覽器JavaScript
- javascript 垃圾回收演算法瞭解一下JavaScript演算法
- 我瞭解到的JavaScript非同步程式設計JavaScript非同步程式設計
- 輕鬆學習 JavaScript(1):瞭解 let 語句JavaScript
- 手擼 JavaScript 模板引擎JavaScript
- JavaScript模板引擎綜述JavaScript
- 解讀 JavaScript 之引擎、執行時和堆疊呼叫JavaScript
- 模擬實現 JS 引擎:深入瞭解 JS機制 以及 Microtask and MacrotaskJSMac
- SEO是什麼意思:全面瞭解搜尋引擎最佳化概念
- 深入瞭解JavaScript執行過程(JS系列之一)JavaScriptJS
- 帶你瞭解JavaScript的執行機制—Event LoopJavaScriptOOP
- JavaScript中的型別判斷,瞭解一下?JavaScript型別
- 你應該瞭解的 5 個 JavaScript 除錯技巧JavaScript除錯
- 10張圖幫你全面瞭解JavaScript基礎知識JavaScript
- JavaScript 中對記憶體的一些瞭解JavaScript記憶體