1.用處
- chrome瀏覽器的引擎
- Nodejs的運行時環境
- electron的底層引擎
2.什么是V8引擎
- 是用C++編寫的Google開源高性能JS和WebAssembly引擎
- 簡而言之:是一個接收JS代碼,編譯代碼然后執行的C++程序,編譯后的代碼可以在多種操作系統,多種處理器上運行
主要的工作:
- 編譯和執行JS代碼
- 處理調用棧
- 內存的分配
- 垃圾的回收
3.溯源
大部分JS引擎在編譯和執行JS代碼都會用到三個重要的組件:
- 解析器
- 負責將JS源代碼解析成抽象語法樹AST
- 解釋器
- 負責將AST解釋成字節碼bytecode
- 也有直接解釋執行bytecode的能力
- 編譯器
- 負責編譯出運行更加高效的機器代碼
早期的V8引擎是如何編譯和執行JS代碼的:
在V8早期5.9版本之前,V8引擎沒有解釋器,卻有兩個編譯器:
- JS由解析器解析后,生成AST抽象語法樹
- 然后由編譯器(Full-codegen)直接使用AST來編譯出機器代碼,而不進行任何中間轉換
- Full-codegen又稱基准編譯器,因為它生成的是一個基准的未被優化的機器代碼
- 還有另一個編譯器(Crankshaft)——優化編譯器:用來優化代碼,提升性能
缺陷:
- 生成的機器碼會占用大量的內存
- 缺少中間的字節碼,很多性能優化策略無法實施——V8性能提升緩慢
- 無法很好的支持和優化JS的新語法特性
4.目前的V8引擎
- 網頁初始化解析執行JS的時間縮短了,網頁能夠更快的onload
- 在生成的優化機器代碼時,不需要從源碼重新編譯,而使用字節碼,並且當需要回退字節碼時,只需要回歸到中間層的字節碼解釋執行就可以了
5.V8引擎中處理JS過程中的一些優化策略
- 如果函數只是聲明而未被調用,則不會被解析生成AST
- 函數如果只被調用一次,bytecode直接被解釋執行
- 函數被調用多次,可能會被標記為熱點函數,可能會被編譯成機器代碼——提高代碼的執行性能。
- 之后執行這個函數時,就直接運行優化后的機器代碼
- 隨着JS代碼的不斷執行,會有更多的代碼被標記為熱點代碼,也就會產生更多的機器代碼
- 此時會有一個問題:回退字節碼。
- 造成的原因是:如一個sum函數,參數是a,b,多次調用傳入整數,且被識別為熱點函數,解釋器將收集到參數和函數信息編譯成優化后的機器碼,這里就會假定了sum函數的參數就是整形的
- 但是如果某次你傳入的不是整數,而是字符串,機器不知道如何處理字符串類型的參數,此時就會deoptimization(回退字節碼)
- 總結:不要把一個變量類型變來變去,傳入的參數的類型也要固定一下