<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          淺析V8引擎,讓你更懂JavaScript!

          共 2765字,需瀏覽 6分鐘

           ·

          2022-03-19 03:46


          導(dǎo)語(yǔ)?|?本文介紹了編譯、解釋、動(dòng)靜態(tài)語(yǔ)言等基本概念,以及V8引擎的基本流程。本文將對(duì)其進(jìn)行詳細(xì)闡述,希望為更多的開(kāi)發(fā)者提供經(jīng)驗(yàn)和幫助。


          一、編譯與解釋


          二進(jìn)制指令就是機(jī)器碼:


          • 編譯:將源代碼一次性轉(zhuǎn)換成目標(biāo)代碼的過(guò)程。執(zhí)行編譯過(guò)程的程序叫編譯器(Compiler)。


          • 解釋:將源代碼逐條轉(zhuǎn)換成目標(biāo)代碼,同時(shí)逐條運(yùn)行的過(guò)程。執(zhí)行解釋過(guò)程的程序叫解釋器(Interpreter)。解釋器一般來(lái)說(shuō)就是vm,vm有兩種,一種是基于堆棧,一種是基于寄存器。


          編譯過(guò)程大致包括詞法分析、語(yǔ)法分析、語(yǔ)義分析、性能優(yōu)化、生成可執(zhí)行文件等五個(gè)步驟,期間涉及到復(fù)雜的算法和硬件架構(gòu)。解釋器與此類似。



          二、靜態(tài)語(yǔ)言與動(dòng)態(tài)語(yǔ)言


          高級(jí)語(yǔ)言按照?qǐng)?zhí)行方式的不同,可分為靜態(tài)語(yǔ)言動(dòng)態(tài)語(yǔ)言


          靜態(tài)語(yǔ)言:使用編譯執(zhí)行的語(yǔ)言,如C、C++、Golang等。使用編譯器一次性生成目標(biāo)代碼,“一次編譯,無(wú)限次運(yùn)行”,程序運(yùn)行速度更快。編譯型語(yǔ)言一般是不能跨平臺(tái)的,也就是不能在不同的操作系統(tǒng)之間隨意切換。


          動(dòng)態(tài)語(yǔ)言:使用解釋執(zhí)行的語(yǔ)言,如Python、Javascript、PHP等。執(zhí)行過(guò)程中需要源代碼,只要存在解釋器,源代碼可以在任何操作系統(tǒng)上運(yùn)行,可移植性好,“一次編寫(xiě),到處運(yùn)行”。



          解釋型語(yǔ)言之所以能夠跨平臺(tái),是因?yàn)橛辛私忉屍鬟@個(gè)中間層。在不同的平臺(tái)下,解釋器會(huì)將相同的源代碼轉(zhuǎn)換成不同的機(jī)器碼,解釋器幫助我們屏蔽了不同平臺(tái)之間的差異。


          java和C#是一種比較奇葩的存在,它們是半編譯半解釋型的語(yǔ)言,源代碼需要先轉(zhuǎn)換成一種中間文件(字節(jié)碼文件),然后再將中間文件拿到虛擬機(jī)中執(zhí)行。Java引領(lǐng)了這種風(fēng)潮,它的初衷是在跨平臺(tái)的同時(shí)兼顧執(zhí)行效率;C#是后來(lái)的跟隨者,但是C#一直止步于Windows平臺(tái),在其它平臺(tái)鮮有作為。


          總結(jié)



          三、V8引擎


          Javascript是解釋型語(yǔ)言,那么V8引擎就對(duì)應(yīng)著解釋器。但是V8引擎為了提高JS的運(yùn)行效率,會(huì)提前編譯。


          也就是V8引擎包括兩個(gè)階段:編譯、執(zhí)行,編譯階段指V8將JavaScript轉(zhuǎn)換為字節(jié)碼或者二進(jìn)制機(jī)器碼,執(zhí)行階段指解釋器解釋執(zhí)行字節(jié)碼,或者CPU直接執(zhí)行二進(jìn)制機(jī)器碼。


          (一)JIT


          V8引擎同時(shí)采用了解釋執(zhí)行和編譯執(zhí)行這兩種方式,也就是在運(yùn)行時(shí)進(jìn)行編譯,這種方式稱為JIT (Just in Time) 即時(shí)編譯。


          V8在執(zhí)行JavaScript源碼時(shí),會(huì)先通過(guò)解析器將源碼解析成AST,解釋器會(huì)將AST轉(zhuǎn)化為字節(jié)碼,一邊解釋一遍執(zhí)行。


          解釋器同時(shí)會(huì)記錄某一代碼片段的執(zhí)行次數(shù),如果執(zhí)行次數(shù)超過(guò)了某個(gè)閾值,這段代碼便會(huì)被標(biāo)記為熱代碼(Hot Code),同時(shí)將運(yùn)行信息反饋給優(yōu)化編譯器TurboFan,TurboFan根據(jù)反饋信息,會(huì)優(yōu)化并編譯字節(jié)碼,最后生成優(yōu)化的機(jī)器碼。



          (二)Parser生成抽象語(yǔ)法樹(shù)


          Parser生成AST抽象語(yǔ)法樹(shù)過(guò)程包括語(yǔ)法分析、詞法分析,和Babel等工具差不多。


          生成AST中的一個(gè)優(yōu)化是惰性解析(Lazy Parsing),因?yàn)樵创a在執(zhí)行前如果全部完全解析的話,不僅執(zhí)行時(shí)間過(guò)長(zhǎng),而且會(huì)消耗更多的內(nèi)存。


          惰性解析就是指如果遇到并不是立即執(zhí)行的函數(shù),只會(huì)對(duì)其進(jìn)行預(yù)解析(Pre-Parser),當(dāng)函數(shù)被調(diào)用時(shí),才會(huì)對(duì)其完全解析。


          預(yù)解析時(shí),只會(huì)驗(yàn)證函數(shù)的語(yǔ)法是否有效、解析函數(shù)聲明以及確定函數(shù)作用域,并不會(huì)生成AST,這項(xiàng)工作由Pre-Parser預(yù)解析器完成。



          (三)Ignition生成字節(jié)碼


          字節(jié)碼是機(jī)器碼的抽象,可以看作是小型的構(gòu)建塊。相比機(jī)器碼,字節(jié)碼不僅占用內(nèi)存少,而且生成字節(jié)碼的時(shí)間很快,提升了啟動(dòng)速度。


          另外,字節(jié)碼與特定類型的機(jī)器碼無(wú)關(guān),通過(guò)解釋器將字節(jié)碼轉(zhuǎn)換為機(jī)器碼后才可以執(zhí)行,這樣也使得V8更加方便的移植到不同的CPU架構(gòu)。


          可以通過(guò)如下命令,查看JavaScript代碼生成的字節(jié)碼。


          node --print-bytecode index.js


          注意,解釋器執(zhí)行字節(jié)碼前,還是會(huì)將字節(jié)碼轉(zhuǎn)為機(jī)器碼,因?yàn)橛?jì)算機(jī)只識(shí)別機(jī)器碼。



          (四)TurboFan


          Ignition執(zhí)行上一步生成的字節(jié)碼,并記錄代碼運(yùn)行的次數(shù)等信息,如果同一段代碼執(zhí)行了很多次,就會(huì)被標(biāo)記為 “HotSpot”(熱點(diǎn)代碼),然后把這段代碼發(fā)送給 編譯器TurboFan。


          然后TurboFan把它編譯為更高效的機(jī)器碼儲(chǔ)存起來(lái),等到下次再執(zhí)行到這段代碼時(shí),就會(huì)用現(xiàn)在的機(jī)器碼替換原來(lái)的字節(jié)碼進(jìn)行執(zhí)行,這樣大大提升了代碼的執(zhí)行效率。


          另外,當(dāng)TurboFan判斷一段代碼不再為熱點(diǎn)代碼的時(shí)候,會(huì)執(zhí)行去優(yōu)化的過(guò)程,把優(yōu)化的機(jī)器碼丟掉,然后執(zhí)行過(guò)程回到Ignition。


          TurboFan做的優(yōu)化包括內(nèi)聯(lián)(inlining)和逃逸分析(Escape Analysis)。


          內(nèi)聯(lián)就是將相關(guān)聯(lián)的函數(shù)進(jìn)行合并,減少運(yùn)行時(shí)間。比如:


          function add(a, b) {  return a + b}function foo() {  return add(2, 4)}


          內(nèi)聯(lián)處理后:


          function fooAddInlined() {  var a = 2  var b = 4  var addReturnValue = a + b  return addReturnValue}
          // 因?yàn)?fooAddInlined 中 a 和 b 的值都是確定的,所以可以進(jìn)一步優(yōu)化function fooAddInlined() { return 6}


          逃逸分析就是分析對(duì)象的生命周期是否僅限于當(dāng)前函數(shù),如果是的話會(huì)對(duì)其進(jìn)行優(yōu)化。比如:


          function add(a, b){  const obj = { x: a, y: b }  return obj.x + obj.y}


          會(huì)處理成:


          function add(a, b){  const obj_x = a  const obj_y = b  return obj_x + obj_y}


          四、總體流程



          參考資料:

          1.v8

          2.編譯型語(yǔ)言和解釋型語(yǔ)言的區(qū)別

          3.編譯器與解釋器的區(qū)別

          4.js引擎能做到多小

          5.深入理解JS引擎

          6.V8是如何執(zhí)行JavaScript代碼的

          7.JIT為什么能大幅度提升性能

          8.JIT(just-in-time)即時(shí)編譯



          ?作者簡(jiǎn)介


          楊國(guó)旺

          騰訊前端開(kāi)發(fā)工程師

          騰訊前端開(kāi)發(fā)工程師,歡迎討論前端問(wèn)題。



          ?推薦閱讀


          圖文解讀:推薦算法架構(gòu)——精排!

          揭秘一致性Hash算法應(yīng)用!

          手把手教你從0開(kāi)始實(shí)現(xiàn)C++協(xié)程!

          閱見(jiàn)深我,讀享生活,TVP讀書(shū)分享會(huì)帶你解鎖新知!



          瀏覽 61
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜精品久久99热蜜桃剧情介绍 | 真正免费av| 久久午夜福利电影 | 国产一区二区三区乱伦 | AⅤ在线观看 |