標籤:

大齡電力汪前端學習路(頁面渲染篇)

前一段時間跟著老師一起學習了關於瀏覽器頁面渲染的一些知識,今天閑下來就寫篇文章給大家分享一下,也算是對自己所學知識的一種鞏固和加深吧。過程涉及借鑒網路資料,如有雷同,請直接與我聯繫。

瀏覽器頁面渲染涉及以下四個步驟:

  1. 瀏覽器根據HTML文件進行解析,得到DOM樹(document object model文檔對象模型,之所以稱之為DOM樹是因為整個文檔對象是非常複雜的父子關係,與樹形結構類似)
  2. 瀏覽器根據我們的CSS文件進行解析,得到CSSOM樹(css object modelCSS對象模型,類似DOM樹)
  3. 瀏覽器將上述解析得到的DOM和CSSOM文件,結合到一起得到render tree (渲染樹)
  4. 瀏覽器根據render tree的文件進行布局,然後將裡面內容繪製、渲染在我們的屏幕上

渲染機制

瀏覽器在進行頁面渲染的時候,主要影響其渲染時間的有reflow(迴流),repaint(重繪)這兩項。

reflow(迴流)

頁面為什麼會慢?那是因為瀏覽器要花時間、花精力去渲染,尤其是當它發現某個部分發生變化影響了布局,需要倒回去重新渲染, 該過程稱為reflow(迴流)。

reflow 幾乎是無法避免的。現在界面上流行的一些效果,比如樹狀目錄的摺疊、展開(實質上是元素的顯 示與隱藏)等,都將引起瀏覽器的 reflow。滑鼠滑過、點擊等,只要這些行為引起了頁面上某些元素的佔位面積、定位方式、邊距等屬性的變化,都會引起它內部、周圍甚至整個頁面的重新渲染。通常我們都無法預估瀏覽器到底會 reflow 哪一部分的代碼,它們都彼此相互影響著。

repaint(重繪)

如果只是改變某個元素的背景色、文字顏色、邊框顏色等等不影響它周圍或內部布局的屬性,將只會引起瀏覽器 repaint(重繪)。

很顯然repaint 的速度明顯快於 reflow(在IE下需要換一下說法,reflow 要比 repaint 更緩慢)。所以我們要盡量避免repaint發生。

載入機制

CSS載入(非同步載入)

在瀏覽器解析HTML文件的時候,如果遇到<link rel="stylesheet" href="style.css">標籤的,就向伺服器放出請求來獲得對應的css文件,與此同時瀏覽器繼續往下解析HTML文件,構建DOM樹,載入css文件的時候,瀏覽器仍可以繼續做其它工作,這就是我們所說的非同步載入,所以我們一般在頁面的首部就引入css文件。那麼如果css文件較大,DOM樹已經構建完成很久,CSSOM還沒有構建完成會出現什麼情況呢?不同的瀏覽器有不同的做法,比如chrome認為,樣式都沒有,painting(繪製)是沒有意義的,於是chrome會出現白屏,直到CSSOM構建完成;firefox觀點與chrome不同,firefox認為還是給用戶看點東西吧,就算樣式還沒載入好,要不人家用戶以為咱瀏覽器出現問題了把咱給卸載了咋辦,於是firefox會先給用戶看點東西,等到CSSOM載入好了又突然把樣式給加上了,嚇用戶一跳,這就是我們說的無樣式內容閃爍

JavaScript載入(同步載入)

在瀏覽器解析HTML的時候,遇到<script>標籤立即開始載入javaScript並執行,這個過程會阻塞後面內容的呈現,也就是說後面的標籤必須要在javaScript執行完成後才進行載入,同時也會阻塞後面組件的載入,這就是我們說的同步載入。顯然我們在頁面上使用javaScript的時候,如果位置放置不當,將會嚴重影響瀏覽器渲染的效率,所以我們一般把javaScript放在頁面的最底部,避免瀏覽器在解析javaScript的時候出現資源阻塞。如果把script標籤放在頁面的首部且javaScript文件過大載入需要花很長的時間的話,頁面會出現較長時間的白屏。

由上述內容我們可以很清楚的知道,JavaScript的載入會對我們的頁面渲染造成很大的影響,那麼我們有沒有辦法盡量減少JavaScript的載入對頁面渲染的影響呢?一般我們可以將<script>標籤放在HTML文件的地步來盡量減小JavaScript載入對我們頁面渲染的影響,在這就涉及到JavaScript的三種屬性。

  1. <script src="script.js"></script>沒有 deferasync,瀏覽器會立即載入並執行指定的腳本,「立即」指的是在渲染該 script 標籤之下的文檔元素之前,也就是說不等待後續載入的文檔元素,讀到就載入並執行。
  2. <script defer src="myscript.js"></script> defer,載入後續文檔元素的過程將和 script.js 的載入並行進行(非同步),但是 script.js 的執行要在所有元素解析完成之後,DOMContentLoaded 事件觸發之前完成。
  3. <script async src="script.js"></script>async,載入和渲染後續文檔元素的過程將和 script.js 的載入與執行並行進行(非同步)。

如果上述內容,還是無法看明白的話,下圖就可以更加清晰直觀的進行理解:

藍色線代表網路讀取,紅色線代表執行時間,這倆都是針對腳本的;綠色線代表 HTML 解析。

此圖告訴我們以下幾個要點:

  1. defer 和 async 在網路讀取(下載)這塊兒是一樣的,都是非同步的(相較於 HTML 解析)
  2. 它倆的差別在於腳本下載完之後何時執行,顯然 defer 是最接近我們對於應用腳本載入和執行的要求的
  3. 關於 defer,此圖未盡之處在於它是按照載入順序執行腳本的,即誰先載入完即誰先執行。
  4. async 則是一個亂序執行的主,反正對它來說腳本的載入和執行是緊緊挨著的,所以不管你聲明的順序如何,只要它載入完了就會立刻執行
  5. 仔細想想,async 對於應用腳本的用處不大,因為它完全不考慮依賴(哪怕是最低級的順序執行),不過它對於那些可以不依賴任何腳本或不被任何腳本依賴的腳本來說卻是非常合適的,最典型的例子:Google Analytics

以上即為我自己對頁面渲染的一些心得,綜合了一些網路大牛的文章,希望可以對大家有所幫助,如有問題,請直接與我聯繫。


推薦閱讀:

你能夠想到多少種讓元素居中的方法?
《Oli-Zhao的前端一萬小時》之:工欲善其事,必先利其器——軟體安裝、環境搭建
可能是最全的 Node.js 9 新特性整理
十年web前端開發工程師告訴你怎樣零基礎入門
愛搞事情的webpack

TAG:前端入門 |