前端工具和框架的自身更新速度很是塊,並且還不斷有新的出現。要想追遇上前端工具和框架的更新速度,你就須要抓住那些本質的知識,而後才能更加輕鬆地理解這些上層應用。好比咱們接下來要介紹的 V8 執行機制,能幫助你從底層瞭解 JavaScript,也能幫助你深刻理解語言轉換器 Babel、語法檢查工具 ESLint、前端框架 Vue 和 React 的一些底層實現機制。要深刻理解 V8 的工做原理,你須要搞清楚一些概念和原理,好比接下來咱們要詳細講解的「編譯器(Compiler)、解釋器(Interpreter)、抽象語法樹(AST)、字節碼(Bytecode)、即時編譯器(JIT)等」概念。前端
之因此存在編譯器和解釋器,是由於機器不能直接理解咱們所寫的代碼,因此在執行程序以前,須要將咱們所寫的代碼「翻譯」成機器能讀懂的機器語言。按語言的執行流程,能夠把語言劃分爲編譯型語言和解釋型語言。瀏覽器
具體流程你能夠參考下圖: 緩存
從圖中你能夠看出這兩者的執行流程,大體可闡述爲以下:性能優化
瞭解了編譯器和解釋器,接下來咱們分析 V8是如何執行一段代碼的,流程以下: 前端框架
V8 在執行過程當中既有解釋器 Ignition,又有編譯器 TurboFan,具體流程:markdown
高級語言是開發者能夠理解的語言,可是讓編譯器或者解釋器來理解就很是困難了。對於編譯器或者解釋器來講,它們能夠理解的就是 AST 了。因此不管你使用的是解釋型語言仍是編譯型語言,在編譯過程當中,它們都會生成一個 AST。這和渲染引擎將 HTML 格式文件轉換爲計算機能夠理解的 DOM 樹的狀況相似。網絡
生成 AST 須要通過兩個階段:架構
這就是 AST 的生成過程,先分詞,再解析。有了 AST 後,那接下來 V8 就會生成該段代碼的執行上下文。框架
有了 AST 和執行上下文後,那接下來的第二步,解釋器 Ignition 就登場了,它會根據 AST 生成字節碼,並解釋執行字節碼。工具
「字節碼就是介於 AST 和機器碼之間的一種代碼。可是與特定類型的機器碼無關,字節碼須要經過解釋器將其轉換爲機器碼後才能執行。」 機器碼所佔用的空間遠遠超過了字節碼,因此使用字節碼能夠減小系統的內存使用。
一般,若是有一段第一次執行的字節碼,解釋器 Ignition 會逐條解釋執行。到了這裏,相信你已經發現了,解釋器 Ignition 除了負責生成字節碼以外,它還有另一個做用,就是解釋執行字節碼。在 Ignition 執行字節碼的過程當中,若是發現有熱點代碼(HotSpot),好比一段代碼被重複執行屢次,這種就稱爲「熱點代碼」,那麼後臺的編譯器 TurboFan 就會把該段熱點的字節碼編譯爲高效的機器碼,而後當再次執行這段被優化的代碼時,只須要執行編譯後的機器碼就能夠了,這樣就大大提高了代碼的執行效率。
字節碼配合解釋器和編譯器是最近一段時間很火的技術,好比 Java 和 Python 的虛擬機也都是基於這種技術實現的,咱們把這種技術稱爲「即時編譯(JIT)」。具體到 V8,就是指解釋器 Ignition 在解釋執行字節碼的同時,收集代碼信息,當它發現某一部分代碼變熱了以後,TurboFan 編譯器便閃亮登場,把熱點的字節碼轉換爲機器碼,並把轉換後的機器碼保存起來,以備下次使用。
雖然在 V8 誕生之初,也出現過一系列針對 V8 而專門優化 JavaScript 性能的方案,好比隱藏類、內聯緩存等概念都是那時候提出來的。不過隨着 V8 的架構調整,你愈來愈不須要這些微優化策略了,相反,對於優化 JavaScript 執行效率,你應該將優化的中心聚焦在單次腳本的執行時間和腳本的網絡下載上,主要關注如下三點內容:
本文使用 mdnice 排版