1. 瀏覽器核心的兩個組成部分html
渲染引擎瀏覽器
將網頁代碼渲染爲用戶視覺能夠感知的平面文檔緩存
1. 解析代碼:HTML 代碼解析爲 DOM,CSS 代碼解析爲 CSSOM(CSS Object Model)。
2. 對象合成:將 DOM 和 CSSOM 合成一棵渲染樹(render tree)。
3. 佈局:計算出渲染樹的佈局(layout)。
4. 繪製:將 渲染樹 繪製到屏幕服務器
每每第一步還沒完成,第二步和第三步就已經開始了。async
因此,會看到這種狀況:網頁的 HTML 代碼還沒下載完,但瀏覽器已經顯示出內容了ide
重流 和 重繪並不必定一塊兒發生,佈局
重流必然致使重繪,重繪不必定須要重流。flex
好比spa
好比,重繪 table
佈局 和 flex
佈局,開銷都會比較大線程
儘可能不要變更高層的 DOM 元素
不要一項一項地改變樣式,而是使用 CSS class 一次性改變樣式
JavaScript 引擎
主要做用是,讀取網頁中的 JavaScript 代碼,對其處理後運行
缺點: 是每次運行都要調用解釋器,系統開銷較大,運行速度慢於編譯型語言
早期解決:
進行必定程度的編譯,生成相似字節碼(bytecode)的中間代碼,以提升運行速度
逐行解釋將字節碼轉爲機器碼,仍是很低效的
現在:
採用「即時編譯」(Just In Time compiler,縮寫 JIT)
即字節碼只在運行時編譯,用到哪一行就編譯哪一行,而且把編譯結果緩存(inline cache)。
一般,一個程序被常常用到的,只是其中一小部分代碼,有了緩存的編譯結果,整個程序的運行速度就會顯著提高
有的 JavaScript 虛擬機基於源碼,即只要有可能,就經過 JIT(just in time
編譯器直接把源碼編譯成機器碼運行,省略字節碼步驟。
2. 通常的網頁加載流程
緣由是 JavaScript 代碼能夠修改 DOM,因此必須把控制權讓給它,不然會致使複雜的線程競賽的問題。
若是外部腳本加載時間很長(一直沒法完成下載),那麼瀏覽器就會一直等待腳本下載完成,形成網頁長時間失去響應,瀏覽器就會呈現「假死」狀態,這被稱爲「阻塞效應」。
此外,對於來自同一個域名的資源,好比腳本文件、樣式表文件、圖片文件等,瀏覽器通常有限制,同時最多下載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 網頁。
一旦採用這個屬性,就沒法保證腳本的執行順序。
哪一個腳本先下載結束,就先執行那個腳本