前言
首先需要明白的是,機器是讀不懂 JS 代碼,機器只能理解特定的機器碼,那如果要讓 JS 的邏輯在機器上運行起來,就必須將 JS 的代碼翻譯成機器碼,然後讓機器識別。JS屬於解釋型語言,對於解釋型的語言說,解釋器會對源代碼做如下分析:
- 解釋器進行詞法分析和語法分析
- 根據語法分析結果生成抽象語法樹
- 生成字節碼
1.ATS抽象語法樹的生成
抽象語法樹生成經過詞法解析和語法解析。
詞法解析就是解析js代碼的每個詞的含義,不考慮他的語法。如下let name='sanyuan'
的詞法解析
再經過語法解析:比如下面的例子轉換成語法解析樹
let name = 'sanyuan'
console.log(name)
2.生成字節碼
什麼是字節碼呢?
字節碼是介於AST 和 機器碼之間的一種代碼,但是與特定類型的機器碼無關,字節碼需要通過解釋器將其轉換爲機器碼然後執行。
我們知道瀏覽器中運行的不是字節碼,是機器碼,那爲什麼要多次一舉呢?
早期的V8引擎是直接轉換成機器碼,但是由於機器碼體積相比字節碼大很多,內存的使用效果不好。那麼可能會問字節碼是怎麼轉換成機器碼解決內存的問題呢?
字節碼不是同時全部轉換成機器碼,而是一行一行的轉換。通過解釋器來逐行執行字節碼,省去了生成二進制文件的操作,這樣就大大降低了內存的壓力。
3.執行代碼
執行代碼就是執行字節碼,這裏會引入一些新的概念
熱點代碼
:js語句轉換的字節碼中相同的代碼就叫熱點代碼。
然後將這個熱點代碼用編譯器
將機器碼保存起來,便於下次使用。這裏有了新一新東西,V8的編譯器
.這麼做的好處是提高了執行效率,下次遇到想通的字節碼直接使用保存的機器碼減少了轉換的過程,有點類似於算法中的動態規劃。
其實當你聽到有人說 JS 就是一門解釋器語言的時候,其實這個說法是有問題的。因爲字節碼不僅配合瞭解釋器,而且還和編譯器打交道,所以 JS 並不是完全的解釋型語言。而編譯器和解釋器的 根本區別在於前者會編譯生成二進制文件但後者不會。
總結
總結一下v8引擎中執行一段js代碼的過程
- 詞法分析和語法分析成語法抽象樹
- 根據語法抽象樹轉換爲字節碼
(上述兩部是解釋器的事情) - 執行字節碼,編譯器將字節碼逐行轉換成機器碼。執行的過程中如果有熱點代碼就不會再將熱點代碼轉換爲機器碼,而是直接使用之前保存好的機器碼
參考
神三元大大的:第26篇: 描述一下 V8 執行一段JS代碼的過程?