JavaScript 很酷,但是 JS 引擎是如何才能理解我們編寫的代碼呢?作為 JS 開發(fā)人員铣墨,我們通常不需要自己處理編譯器室埋。然而,了解 JS 引擎的基礎(chǔ)知識并了解它如何處理JS代碼伊约,并將其轉(zhuǎn)換成機器能夠理解的東西姚淆,絕對是個有益無害的事情。
注意:本文主要基于 Node.js 和基于 Chrome 的瀏覽器使用的 V8 引擎屡律。
HTML解析器遇到帶有源代碼的script標簽腌逢。來自此源的代碼從網(wǎng)絡(luò),緩存或已安裝的服務(wù)工作程序中加載超埋。響應(yīng)是將請求的腳本作為字節(jié)流搏讶,由字節(jié)流解碼器負責(zé)。字節(jié)流解碼器在下載字節(jié)流時對其進行解碼霍殴。
字節(jié)流解碼器從已解碼的字節(jié)流中創(chuàng)建令牌媒惕。例如,0066解碼為f, 0075到u,006e到n, 0063到c, 0074到t, 0069到i, 006f到o, 006e到n来庭,后面跟一個空格妒蔚。就像JS中的function,這是 JS 中的一個保留關(guān)鍵字,它會創(chuàng)建一個標記肴盏,并將其發(fā)送給解析器科盛。對于字節(jié)流的其余部分也是如此。
該引擎使用兩個解析器:預(yù)解析器(pre-parser)和解析器(parser)菜皂。預(yù)解析器只提前檢查標記贞绵,以查看是否有語法錯誤。這可以減少發(fā)現(xiàn)代碼中的錯誤所需的時間恍飘,否則解析器稍后就會發(fā)現(xiàn)這些錯誤榨崩。
如果沒有錯誤,解析器將根據(jù)從字節(jié)流解碼器接收到的標記創(chuàng)建節(jié)點常侣。使用這些節(jié)點蜡饵,它創(chuàng)建了一個抽象語法樹,即AST胳施。
接下來溯祸,輪到解釋器(interpreter)了。遍歷AST并根據(jù)AST包含的信息生成字節(jié)碼的解釋器舞肆。一旦字節(jié)碼完全生成焦辅,AST就會被刪除,從而清除內(nèi)存空間椿胯。最后筷登,生成的機器碼就可以在電腦上運行了。
雖然字節(jié)碼很快哩盲,但它可以更快前方。當這個字節(jié)碼運行時,將生成信息廉油。它可以檢測某些行為是否經(jīng)常發(fā)生惠险,以及所使用數(shù)據(jù)的類型。也許已經(jīng)調(diào)用一個函數(shù)幾十次了:現(xiàn)在是時候優(yōu)化它了抒线,這樣它會運行得更快!
字節(jié)碼與生成的類型反饋一起發(fā)送到優(yōu)化編譯器(ptimizing compiler)班巩。優(yōu)化的編譯器接收字節(jié)碼和類型反饋,并根據(jù)這些信息生成高度優(yōu)化的機器碼嘶炭。
JS 是一種動態(tài)類型語言抱慌,這意味著數(shù)據(jù)類型可以不斷變化。如果 JS引擎每次都要檢查某個值的數(shù)據(jù)類型眨猎,那么速度會非常慢抑进。
相反,JS 引擎使用一種稱為內(nèi)聯(lián)緩存(inline caching)的技術(shù)睡陪。它將代碼緩存在內(nèi)存中寺渗,希望將來它會以相同的行為返回相同的值.假設(shè)某個函數(shù)被調(diào)用100次夕凝,并且到目前為止總是返回相同的值。它將假設(shè)在第101次調(diào)用它時也會返回這個值户秤。
假設(shè)我們有以下函數(shù)sum,(到目前為止)每次都使用數(shù)值作為參數(shù)來調(diào)用它:
ffunction sum(a, b){
? return a + b
}
sum(1, 2)
執(zhí)行結(jié)果為 3逮矛。下次調(diào)用它時鸡号,它將假定我們再次使用兩個相同數(shù)字對其進行調(diào)用。
那么就不需要動態(tài)查找须鼎,只需要使用存儲在特定內(nèi)存槽中的結(jié)果鲸伴,該槽已經(jīng)有一個引用。否則晋控,如果假設(shè)不正確汞窗,它將反優(yōu)化代碼并恢復(fù)到原始字節(jié)碼,而不是優(yōu)化后的機器碼赡译。
例如仲吏,下一次調(diào)用它時,我們傳遞的是字符串而不是數(shù)字蝌焚。因為 JS 是動態(tài)類型的裹唆,所以這樣做不會有任何錯誤。
function sum(a, b){
? return a + b
}
sum('1', 2)
這意味著數(shù)字2將被強制轉(zhuǎn)換成字符串只洒,而函數(shù)將返回字符串'12'许帐。它返回執(zhí)行解釋的字節(jié)碼并更新類型反饋。
我希望這篇文章對你有用!當然毕谴,在這篇文章中還沒有涉及到引擎的更多部分(JS堆成畦,調(diào)用堆棧,等等)涝开,后續(xù)會繼續(xù)分享循帐。如果你對 JS 的內(nèi)部機制感興趣,強烈建議自己可以做一些研究忠寻,V8 是開源的惧浴,并且有一些很棒的文檔說明它是如何工作的。
https://dev.to/lydiahallie/javascript-visualized-the-javascript-engine-4cdf