藉助performance工具直觀理解瀏覽器的渲染過程

前言

在學習前端的過程當中,你們都會對瀏覽器這個神祕的盒子感到好奇
從輸入一串url到頁面解析渲染完成,瀏覽器都幹了些啥?css

直觀展現

爲了更好的理解這個過程,咱們使用一個工具來幫助咱們
Chrome自帶的開發工具中的performance(老版本和其餘瀏覽器爲timelinehtml

clipboard.png

點擊錄製,而後在地址欄輸入咱們的url
這裏以百度爲例,輸入www.baidu.com,回車
而後點擊錄製結束,就能看到這個東西前端

clipboard.png

網絡請求

咱們最早看到的是這個git

clipboard.png

字面意思就能夠理解,瀏覽器在向服務器發送請求,並接收響應頭和響應體
不過實際上在這以前,瀏覽器還作了一些事
得先知道朝哪一個服務器發送請求吧github

  1. 根據url,先去本地DNS緩存列表裏尋找對應的服務器的ip地址和端口號,若沒有找到,繼續尋找系統緩存和路由緩存,若找到則跳轉第三步
  2. 還沒找到的話則請求本地DNS服務器,沒有就將域名發送給其餘服務器,遞歸尋找,從根域名服務器開始不斷向下遞歸,直到返回對應的IP地址和端口號,並將其緩存
  3. 根據ip地址和端口號,與目標服務器創建TCP鏈接(三次握手)

這三步並無被咱們看見,而後接下來的事就被咱們觀察到了
瀏覽器向服務器發送http請求,並接收返回的響應頭和響應體segmentfault

繼續往下看數組

clipboard.png
黃色部分都是瀏覽器的一些默認行爲,其中包括隱藏原本的標籤頁內容等等
以及下面的Recalculate Style(從新計算樣式),Layout(重排)是爲清空原本的頁面,爲新頁面作準備
這些不用管它,不過在這中間咱們又一次看到了Receive Data
那是由於服務器在發送數據的時候,可能會進行拆包,分幾回發送瀏覽器

解析html

瀏覽器比較勤快,它並不會等html徹底接收完纔開始解析,而是接受一部分就開始解析一部分緩存

clipboard.png

HTML Parser的任務是將HTML標記,解析成DOM Tree,這是一個深度遍歷的過程,只有Dom下的子節點都被遍歷完成,才遍歷下一個同級Dom節點性能優化

clipboard.png
同時,在解析的過程當中,若是遇到了圖片,link標籤,script標籤,都會向服務器發送請求
例如咱們上圖,遇到了百度的logo圖片,就請求下載

clipboard.png

js解析

clipboard.png
遇到js就當即解析下載執行執行

clipboard.png
不論是內聯的仍是外部的,都會阻塞後續dom的解析和渲染
因此通常將<script>標籤放在<body>後面

若是是外部的,還能夠在<script>標籤上加上deferasync屬性
defer可讓js的下載不影響html的後續解析,且在html解析完了再執行js文件,且按照原來的下載順序
async也是讓js的下載不影響html的後續解析,但一旦下載完了就當即執行,所以也沒法保證按照下載順序執行

css解析

遇到內聯的css樣式就開始解析

clipboard.png

外部的css文件,則在接收到了以後進行解析

clipboard.png

二者都會不會阻塞Dom的解析,但會阻塞Dom的渲染
這也是爲何要把css<link>標籤放進<head>

當css文件放在<head>中時,雖然css解析也會阻塞後續dom的渲染,可是在解析css的同時也在解析dom,因此等到css解析完畢就會逐步的渲染頁面了

css語句解析成爲CSSOM

clipboard.png

渲染布局與繪製

在有了Dom TreeCSSOM以後
瀏覽器就會構建Render Tree(渲染樹)

clipboard.png

其實把DOM Tree和CSSOM進行附加

clipboard.png

因此Render Tree實際上就是一個計算好了樣式,同時不包含display:none之類,不佔據空間的元素的的渲染樹。
而後瀏覽器就根據這個Render Tree進行第一次的佈局(Layout)以及繪製(Paint

clipboard.png

重排和重繪

完成了第一次繪製以後,瀏覽器會繼續收到服務器發來的數據
圖片,css文件,js文件
其中可能會有致使頁面佈局更改或樣式更改的內容,都會添加到咱們的Render Tree上去
引發重排(Layout)或重繪(Paint

clipboard.png

其中重排必定會連帶着引發重繪,反之則否則

重排(Reflow)

引發重排的操做

頁面首次渲染
瀏覽器窗口大小發生改變
元素尺寸或位置發生改變
元素內容變化(文字數量或圖片大小等等)
元素字體大小變化
添加或者刪除可見的DOM元素
激活CSS僞類(例如::hover)
設置style屬性

那是遇到一次就重排一次嗎?也不是
瀏覽器會有一個渲染隊列來進行優化
積累了必定量或必定時間的更改內容,纔會進行重排

不過當訪問了特定屬性的時候
好比js文件裏遇到一句console.log(body.clientWidth)
會強制刷新渲染隊列
如下屬性的訪問會當即刷新渲染隊列

widthheight margin padding display border
position overflow clientWidth clientHeight clientTop
clientLeft offsetWidth offsetHeight offsetTop offsetLeft
scrollWidth scrollHeight scrollTop scrollLeft scrollIntoView()
scrollTo() getComputedStyle() getBoundingClientRect() scrollIntoViewIfNeeded()

因此訪問這些屬性要謹慎,最好分離讀寫,以避免過多的重排影響性能

重繪

引發重繪的通常都是修改元素的屬性

color border-style visibility background
text-decoration background-image background-position background-repeat
outline-color outline outline-style border-radius
outline-width box-shadow background-size

性能優化

從性能優化的角度,咱們要儘可能減小瀏覽器的重排和重繪,尤爲是重排

  1. 儘可能不要在佈局信息改變時作查詢(會致使渲染隊列強制刷新)
  2. 減小DOM操做,同一個DOM的多個屬性改變能夠寫在一塊兒,在一個局部方法中須要屢次訪問同一個Dom,則先暫存它的引用。批量添加DOM,能夠先讓元素脫離文檔流,操做完後再帶入文檔流,這樣只會觸發一次重排(應用fragment元素)
  3. 將須要屢次重排的元素,position屬性設爲absolutefixed,例若有動畫效果的元素
  4. 採用更優的API替代消費高的API,轉換優化消費高的集合,如用querySelectorAll()替代getElementByXX()
  5. 開啓動畫的GPU加速
  6. 少用HTML集合(類數組)來遍歷,由於集合遍歷比真數組遍歷耗費更高。
  7. 用事件委託來減小事件處理器的數量。
  8. 避免設置大量的style屬性,由於經過每一次設置都會觸發一次reflow,因此最好是使用class屬性
  9. 動畫實現的速度太精細平滑,會致使reflow過於頻繁
  10. 不要使用table佈局,由於table中某個元素旦觸發了reflow,那麼整個表格都會reflow。能夠設置table-layout:auto;或者是table-layout:fixed這樣能夠只reflow一行,
  11. 減小經過JavaScript代碼修改元素樣式,儘可能使用修改class名方式操做樣式或動畫;
  12. 隱藏在屏幕外,或在頁面滾動時,儘可能中止動畫;

最後

你們能夠本身去嘗試一下performance的使用,能夠更直觀的理解瀏覽器的工做流程

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

參考文章

https://segmentfault.com/a/11...
https://segmentfault.com/a/11...
https://sylvanassun.github.io...
https://www.imooc.com/article...
https://segmentfault.com/a/11...

相關文章
相關標籤/搜索