今天我們來聊聊js引擎
JAVAScript很酷,但是機(jī)器如何才能真正理解您編寫的代碼?作為JavaScript開發(fā)人員,我們通常不必自己處理編譯器。但是,一定要了解JavaScript引擎的基礎(chǔ)知識(shí),看看它如何處理我們?nèi)祟愑押玫腏S代碼,并將其轉(zhuǎn)變?yōu)闄C(jī)器可以理解的東西!
|注意: 實(shí)現(xiàn)基于Node.js和基于Chromium的瀏覽器使用的V8引擎。
html解析器遇到script帶有源的標(biāo)記。來自script的代碼從網(wǎng)絡(luò),緩存或已安裝的service worker中加載。請(qǐng)求腳本作為一個(gè)字節(jié)流被響應(yīng),該字節(jié)流被字節(jié)流解碼器處理!字節(jié)流解碼器對(duì)字節(jié)流進(jìn)行解碼,一旦它被下載。
字節(jié)流解碼器從解碼的字節(jié)流中創(chuàng)建token。例如,0066解碼為f, 0075解碼為u, 006e解碼為n,0063解碼為c, 0074解碼為t,0069解碼為i, 006f解碼為o和 006e解碼為n后跟一個(gè)空格。好像你寫function一樣!這是JavaScript中的保留關(guān)鍵字,創(chuàng)建token并將其發(fā)送到解析器(和pre-parser,我沒有在gif中介紹,但稍后會(huì)進(jìn)行解釋)。其余字節(jié)流也會(huì)發(fā)生同樣的情況。
引擎使用兩個(gè)解析器:預(yù)解析器和解析器。預(yù)解析器僅及早檢查token,以查看是否存在語法錯(cuò)誤?。這樣可以減少發(fā)現(xiàn)代碼中錯(cuò)誤的數(shù)量,否則解析器稍后會(huì)發(fā)現(xiàn)錯(cuò)誤!
如果沒有錯(cuò)誤,則解析器根據(jù)從字節(jié)流解碼器接收的token創(chuàng)建節(jié)點(diǎn)。使用這些節(jié)點(diǎn),它會(huì)創(chuàng)建一個(gè)抽象語法樹或AST。
接下來,是時(shí)候翻譯了!翻譯器(interpreter)遍歷AST,并根據(jù)AST包含的信息生成字節(jié)碼。字節(jié)代碼生成完畢后,將刪除AST,以清除內(nèi)存空間。最后,我們有一些機(jī)器可以使用的東西!
盡管字節(jié)碼很快,但是可以更快。運(yùn)行此字節(jié)碼時(shí),將生成信息。它可以檢測某些行為是否經(jīng)常發(fā)生,以及所使用的數(shù)據(jù)類型。也許您已經(jīng)調(diào)用了數(shù)十次函數(shù):是時(shí)候?qū)ζ溥M(jìn)行優(yōu)化,使其運(yùn)行得更快了!♀♀?
字節(jié)碼與生成的類型反饋一起被發(fā)送到優(yōu)化編譯器(optimizing compiler)。優(yōu)化編譯器獲取字節(jié)碼和類型反饋,并從中生成高度優(yōu)化的機(jī)器碼。
JavaScript是一種動(dòng)態(tài)類型化的語言,這意味著數(shù)據(jù)類型可以不斷變化。如果JavaScript引擎每次必須檢查某個(gè)值具有哪種數(shù)據(jù)類型,那將非常慢。
相反,引擎使用一種稱為內(nèi)聯(lián)緩存(inline caching)的技術(shù)。它將代碼緩存在內(nèi)存中,以期將來返回具有相同行為的相同值!假設(shè)某個(gè)函數(shù)被調(diào)用了100次,并且到目前為止一直返回相同的值。它將假定它也會(huì)在您第101次調(diào)用它時(shí)返回該值。
假設(shè)我們有以下函數(shù)sum,到目前為止,每次都使用數(shù)值作為參數(shù)來調(diào)用它:
這將返回?cái)?shù)字3!下次調(diào)用它時(shí),它將假定我們?cè)俅问褂脙蓚€(gè)數(shù)值調(diào)用它。
如果是這樣,則不需要?jiǎng)討B(tài)查找,它可以使用存儲(chǔ)在已引用的特定內(nèi)存插槽中的結(jié)果。否則,如果假設(shè)不正確,它將不會(huì)對(duì)代碼進(jìn)行優(yōu)化,并且恢復(fù)為原始字節(jié)代碼,而不是優(yōu)化后的機(jī)器代碼。
例如,下一次調(diào)用它時(shí),我們傳遞的是字符串而不是數(shù)字。由于JavaScript是動(dòng)態(tài)類型的,因此我們可以做到這一點(diǎn)而沒有任何錯(cuò)誤!
這意味著該數(shù)字2將被強(qiáng)制轉(zhuǎn)換為字符串,而該函數(shù)將返回該字符串 "12"。返回執(zhí)行解釋的字節(jié)碼并更新類型反饋。
希望這篇文章對(duì)您有用!當(dāng)然,我在這篇文章中沒有涉及引擎的許多部分(JS堆,調(diào)用堆棧等),如果您對(duì)JavaScript的內(nèi)部結(jié)構(gòu)感興趣,我絕對(duì)鼓勵(lì)您自己開始做一些研究,V8是開源的,并且有一些很好的文檔說明了它的幕后工作方式!
歡迎各位道友留言評(píng)論!!!