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

前言

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

直觀展現

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

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

網絡請求

咱們最早看到的是這個git

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

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

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

繼續往下看數組

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

解析html

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

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

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

js解析

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

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

若是是外部的,還能夠在<script>標籤上加上deferasync屬性

  • defer可讓js的下載不影響html的後續解析,且在html解析完了再執行js文件,且按照原來的下載順序
  • async也是讓js的下載不影響html的後續解析,但一旦下載完了就當即執行,所以也沒法保證按照下載順序執行

css解析

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

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

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

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

css語句解析成爲CSSOM

渲染布局與繪製

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

其實把DOM Tree和CSSOM進行附加

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

重排和重繪

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

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

重排(Reflow)

引發重排的操做

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

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

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

widthheight margin padding
position overflow clientWidth
clientLeft offsetWidth offsetHeight
scrollWidth scrollHeight scrollTop
scrollTo() getComputedStyle() getBoundingClientRect()

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

重繪

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

color border-style visibility
text-decoration background-image background-position
outline-color outline outline-style
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的使用,能夠更直觀的理解瀏覽器的工做流程

事件彙總:

參考文章

segmentfault.com/a/119000000… segmentfault.com/a/119000001… sylvanassun.github.io/2017/10/03/… www.imooc.com/article/459… segmentfault.com/a/119000001…

相關文章
相關標籤/搜索