BOM 瀏覽器對象模型_渲染引擎_JavaScript 引擎_網頁加載流程

1. 瀏覽器核心的兩個組成部分html

渲染引擎瀏覽器

將網頁代碼渲染爲用戶視覺能夠感知的平面文檔緩存

  • 分類:

 

  • Firefox        Gecko 引擎
  • Safari        WebKit 引擎
  • Chrome        Blink 引擎
  • IE        Trident 引擎
  • Edge        EdgeHTML 引擎

 

  • 渲染引擎處理網頁,一般分紅四個階段

1. 解析代碼:HTML 代碼解析爲 DOM,CSS 代碼解析爲 CSSOM(CSS Object Model)。
2. 對象合成:將 DOM 和 CSSOM 合成一棵渲染樹(render tree)。
3. 佈局:計算出渲染樹的佈局(layout)。   
4. 繪製:將 渲染樹 繪製到屏幕服務器

 

每每第一步還沒完成,第二步和第三步就已經開始了。async

因此,會看到這種狀況:網頁的 HTML 代碼還沒下載完,但瀏覽器已經顯示出內容了ide

  • 渲染樹轉換爲網頁佈局,稱爲「佈局流」(flow)
  • 佈局顯示到頁面的這個過程,稱爲「繪製」(paint)

重流 和 重繪並不必定一塊兒發生,佈局

重流必然致使重繪,重繪不必定須要重流。flex

好比spa

  • 改變元素顏色,只會致使重繪,而不會致使重流;
  • 改變元素的佈局,則會致使重繪和重流
  • 做爲開發者,應該儘可能設法下降重繪的次數和成本

好比,重繪 table 佈局 和 flex 佈局,開銷都會比較大線程

儘可能不要變更高層的 DOM 元素

不要一項一項地改變樣式,而是使用 CSS class 一次性改變樣式

 

JavaScript 引擎

主要做用是,讀取網頁中的 JavaScript 代碼,對其處理後運行

  • 解釋型語言,也就是說,它不須要編譯,由解釋器實時運行

缺點: 是每次運行都要調用解釋器,系統開銷較大,運行速度慢於編譯型語言

早期解決:

 進行必定程度的編譯,生成相似字節碼(bytecode)的中間代碼,以提升運行速度

逐行解釋將字節碼轉爲機器碼,仍是很低效的

 

  • 讀取代碼,進行詞法分析(Lexical analysis),將代碼分解成詞元(token)。
  • 對詞元進行語法分析(parsing),將代碼整理成「語法樹」(syntax tree)。
  • 使用「翻譯器」(translator),將代碼轉爲字節碼(bytecode)。
  • 使用「字節碼解釋器」(bytecode interpreter),將字節碼轉爲機器碼。

 

現在:

採用「即時編譯」(Just In Time compiler,縮寫 JIT)

即字節碼只在運行時編譯,用到哪一行就編譯哪一行,而且把編譯結果緩存(inline cache)。

一般,一個程序被常常用到的,只是其中一小部分代碼,有了緩存的編譯結果,整個程序的運行速度就會顯著提高

  • 字節碼不能直接運行,而是運行在一個虛擬機(Virtual Machine)之上,通常也把虛擬機稱爲 JavaScript 引擎
  • 並不是全部的 JavaScript 虛擬機運行時都有字節碼

有的 JavaScript 虛擬機基於源碼,即只要有可能,就經過 JIT(just in time

編譯器直接把源碼編譯成機器碼運行,省略字節碼步驟。

  • 常見 JavaScript 虛擬機

 

  • [Chakra](http://en.wikipedia.org/wiki/Chakra_(JScript_engine))(Microsoft Internet Explorer)
  • Nitro/JavaScript Core (Safari)
  • Carakan (Opera)
  • SpiderMonkey (Firefox)
  • [V8](http://en.wikipedia.org/wiki/V8_(JavaScript_engine)) (Chrome, Chromium)

2. 通常的網頁加載流程

  • 瀏覽器一邊下載 HTML 網頁,一邊開始解析。也就是說,不等到下載完,就開始解析。
  • 解析過程當中,瀏覽器發現 <script> 元素,就暫停解析,把網頁渲染的控制權轉交給 JavaScript 引擎。

緣由是 JavaScript 代碼能夠修改 DOM,因此必須把控制權讓給它,不然會致使複雜的線程競賽的問題。

若是外部腳本加載時間很長(一直沒法完成下載),那麼瀏覽器就會一直等待腳本下載完成,形成網頁長時間失去響應,瀏覽器就會呈現「假死」狀態,這被稱爲「阻塞效應」。

  • 若是 <script> 元素引用了外部腳本,就下載該腳本再執行,不然就直接執行代碼。
  • JavaScript 引擎執行完畢,控制權交還渲染引擎,恢復往下解析 HTML 網頁

此外,對於來自同一個域名的資源,好比腳本文件、樣式表文件、圖片文件等,瀏覽器通常有限制,同時最多下載6~20個資源

即最多同時打開的 TCP 鏈接有限制,這是爲了防止對服務器形成太大壓力

若是是來自不一樣域名的資源,就沒有這個限制。因此,一般把 靜態文件 放在 不一樣的域名之下,以加快下載速度

 

2. 解決「阻塞效應」 ,而 defer、async 關鍵字的 <script>,都不該該使用 document.write
<script src="a.js" defer></script> <script src="b.js" defer></script>

defer 屬性 的運行流程以下:

瀏覽器開始解析 HTML 網頁。
解析過程當中,發現帶有 defer 屬性的 <script> 元素。
瀏覽器繼續往下解析 HTML 網頁,同時並行下載 <script> 元素加載的外部腳本。
瀏覽器完成解析 HTML 網頁,此時再回過頭執行已經下載完成的腳本。

優勢:

有了defer屬性,瀏覽器下載腳本文件的時候,不會阻塞頁面渲染。

下載的腳本文件在 DOMContentLoaded 事件觸發前執行(即剛剛讀取完</html>標籤),

並且能夠保證執行順序就是它們在頁面上出現的順序

 

<script src="a.js" async></script> <script src="b.js" async></script>

使用另外一個進程下載腳本,下載時不會阻塞渲染

 

瀏覽器開始解析 HTML 網頁。
解析過程當中,發現帶有 async 屬性的 script 標籤。
瀏覽器繼續往下解析 HTML 網頁,同時並行下載 <script> 標籤中的外部腳本。
腳本下載完成,瀏覽器暫停解析 HTML 網頁,開始執行下載的腳本。
腳本執行完畢,瀏覽器恢復解析 HTML 網頁。

 

一旦採用這個屬性,就沒法保證腳本的執行順序。

哪一個腳本先下載結束,就先執行那個腳本

相關文章
相關標籤/搜索