JavaScript程式碼是怎麼在瀏覽器裡面運行起來的?

JavaScript程式碼是怎麼在瀏覽器裡面運行的?下面簡單探索一下

瀏覽器內核

瀏覽器內核(Rendering Engine),常見的叫法如:排版引擎、解釋引擎、渲染引擎,現在流行稱為瀏覽器內核。

瀏覽器 內核 說明
IE Trident IE、獵豹安全、360極速瀏覽器、百度瀏覽器
FireFox Gecko 可惜這幾年已經沒落了,打開速度慢、升級頻繁、豬一樣的隊友flash、神一樣的對手chrome。
Safari Webkit 從Safari推出之時起,它的渲染引擎就是Webkit,一提到 webkit,首先想到的便是 chrome,可以說,chrome 將 Webkit內核 深入人心,殊不知,Webkit 的鼻祖其實是 Safari。
Chrome Chromium/Blink 在 Chromium 項目中研發 Blink 渲染引擎(即瀏覽器核心),內置於 Chrome 瀏覽器之中。Blink 其實是 WebKit 的分支。大部分國產瀏覽器最新版都採用Blink內核。二次開發
Opera Blink

瀏覽器渲染過程

  1. HTML首先會被瀏覽器內核中的HTML Parser解析,最終會構建成一顆DOM樹

  2. CSS會被瀏覽器內核中的CSS Parser解析,形成CSS規則,CSS規則和DOM樹結合形成一個渲染樹,通過layout(布局)生成最終的渲染樹。

為什麼要有layout呢?因為要適配不同尺寸的螢幕。有了渲染樹之後就可以繪製展現出來了。

常見的js引擎

  • SpiderMonkey:第一款js引擎,由Brendan Eich開發(js作者)。

  • Chakra:微軟開發,由於IE瀏覽器。

  • JavascriptCore:webkit的js引擎,Apple公司開發。

  • V8:Google開發的強大js引擎,也幫助Chrome從眾多瀏覽器中脫穎而出。

瀏覽器內核和js引擎的關係

這裡用webkit為列,webkit最重要的兩部分:

  1. WebCore: 負責HTML、CSS的解析、布局、渲染等相關工作;
  2. JavascriptCore:解析、執行js程式碼。

下面是Chromium的架構圖

普通JavaScript引擎(笨重)

作用:javascript引擎幫助我們將js程式碼編譯成CPU認識的指令集,最終被cpu執行。

普通JavaScript引擎除了編譯之外還要負責執行以及記憶體管理。 js是解釋形語言,由引擎直接讀取源碼,一邊編譯一邊執行,這樣效率相對較低,而編譯形語言(如c++)是把源碼直接編譯成可直接執行的程式碼執行效率更高。

隨著技術的發展,對JavaScript性能的要求越來越高,V8引擎就是在此背景下產生的,它產生的目的就是為了提高javascript執行的性能。

V8引擎(輕量)

V8引擎是一個JavaScript引擎實現,最初由一些語言方面專家設計,後被Google收購,隨後Google對其進行了開源。

V8使用C++開發,在運行JavaScript之前,相比其它的JavaScript的引擎轉換成位元組碼或解釋執行,V8將其編譯成原生機器碼(IA-32, x86-64, ARM, or MIPS CPUs),並且使用了如內聯快取(inline caching)等方法來提高性能。

將javascript程式碼轉換成AST

V8引擎會先將javascript程式碼轉換成AST(抽象語法樹),事實上所有的程式語言都會將源程式碼解析成抽象語法樹(abstract syntax tree, AST)。

AST是電腦科學中很早的一個概念,不是V8特有的(只是V8在轉換過程中做了非常多的優化),更不是javascript特有的。

AST的用途

AST的作用也不僅僅是用來在V8的編譯上,比如我們常用的babel插件將 es6->es5 、ts->js 、死區分析、Dead Code、編譯壓縮打包、css預處理器、eslint等等,這些功能的實現都離不開AST。

AST編譯過程

V8執行js的簡易流程

  1. 瀏覽器內核將源碼以流的方式交給v8引擎,v8引擎獲取到源碼並進行編碼轉換

  2. 詞法分析Scanner,將程式碼轉成tokens

  3. 語法分析Parser、Preparser,直接將tokens轉換成AST樹結構

  4. 位元組碼生成

  1. parser就是直接將tokens轉換成AST樹結構

  2. preParse稱之為預解析,為什麼需要預解析呢?

  • 這是因為並不是所有的js程式碼一開始就會被執行,如果對所有的js程式碼都進行解析,會影響網頁運行效率。所以v8引擎就實現了延遲解析的方案,將不必要的函數進行預解析,也就是只解析暫時需要的內容,而對函數的全量解析是在函數被調用時才會進行

  • 比如我們在一個函數outer內部定義了另外一個函數inner,那麼inner函數就會進行預解析

下面看一下在線解析AST的示例👇

瀏覽器內核與JS引擎本篇就簡單聊這麼多,先淺淺的了解一下。關於V8的東西很多,也有很多非常絕妙的設計,更多V8相關的戳這裡,一步步解鎖吧!

我是 甜點cc

微信公眾號:【看見另一種可能】

熱愛前端開發,也喜歡專研各種跟本職工作關係不大的技術,技術、產品興趣廣泛且濃厚。本號主要致力於分享個人經驗總結,希望可以給一小部分人一些微小幫助。

希望能和大家一起努力營造一個良好的學習氛圍,為了個人和家庭、為了中國的互聯網物聯網技術、數字化轉型、數字經濟發展做一點點貢獻。數風流人物還看中國、看今朝、看你我。