淺談首屏渲染速度及defer和async的異同

背景

隨着業務功能的增長,Web App的「身軀」變得愈來愈臃腫,性能優化迫在眉睫,而首當其衝的是首屏渲染速度的問題。前端

正文

咱們經常說起首屏渲染速度,可是鮮有人去給它下一個確切的定義。在個人理解裏面,這裏面的速度並非指咱們狹義裏的速度,而是廣義上的。由於咱們沒法準確地統計網絡傳輸所通過的物理里程,故不能用v=s/t去計算。那麼如何廣義法呢?其實,咱們能夠將首屏渲染速度等同爲首屏渲染時間來理解。能夠這麼說,從用戶在瀏覽器地址欄敲入一個url到用戶看到一個完整的頁面,這個過程所花費的時間就是首屏渲染時間。關係到這個首屏渲染時間的長短有不少因素,好比說,DNS解析時間網絡傳輸時間頁面渲染時間等等。今天,咱們就挑其中的一個子環節頁面渲染來講說。頁面渲染是指從瀏覽器接收到從服務器返回的HTML文件那一刻算起,到你眼睛看到一個完整頁面爲止的過程。對於前端開發來講,作首屏渲染速度的優化每每會選擇在頁面渲染這個過程發力。經過優化頁面渲染過程,咱們能夠減小頁面處於白屏狀態的時間,從而達到必定的首屏渲染速度優化效果。瀏覽器

上面只是提到了頁面渲染的一個很表象的說法。其實頁面渲染這個過程包含了一系列的環節,我能夠簡單地描述爲(以下圖):解析HTML構建DOM樹;解析CSS,構建CSSOM tree;而後將DOM tree和CSSOM tree合併爲render tree。再而後使用render tree所提供的數據進行佈局(layout),最後是將整個頁面繪製(paint)到屏幕上。而今天咱們的話題跟這其中一個環節-HTML解析有關。性能優化

瀏覽器在解析HTML文檔的時候,遇到常規的script標籤會停下來,轉而去加載所請求的腳本,緊跟着執行加載回來的腳本。換句話說,使用常規script標籤去請求外部腳本的話,會阻塞當前的HTML解析。而阻塞當前的HTML解析,就是阻塞整個頁面渲染的過程。因此,咱們能夠作的就是使得script標籤引用外部腳本的時候不要阻塞HTML解析。服務器

爲了達到這個目的,咱們一般會採用如下的方案:網絡

  • 把常規的script標籤放置到</ body>標籤前。
  • 給script標籤添加defer,async標誌位,使它的加載與HTML解析並行進行。

到這裏,咱們就引出了咱們今天的兩個主角:defer和async。正如上面所說的,添加了這個標誌位的script標籤都會異步加載腳本。這是它們共同的特性,那麼它們之間又有什麼不一樣的地方呢?異步

它們不一樣的地方體如今兩個方面:async

  1. 腳本的執行是否是緊跟着加載發生的?
  2. 若是文檔中有多個設置了相同標誌位的script標籤,它們的加載順序會是如何?

通過查閱資料和親身實踐,咱們能夠有如下的結論:佈局

對於defer標誌位而言:性能

  1. 添加了defer標誌位的script標籤所加載回來的腳本會在HTML解析完以後,DOMContendLoaded事件發生以前執行。
  2. 若是文檔中有多個設置了defer標誌位的script標籤的話,它們會按照在文檔出現的順序來加載和執行的。

對於async標誌位而言:優化

  1. 添加了async標誌位的script標籤所加載回來的腳本會緊接着就執行了。
  2. 若是文檔中有多個設置了async標誌位的script標籤的話,它們不會按照在文檔出現的順序來加載和執行的,它們都是亂序的主。

從上面兩個結論來看,使用了defer和async標誌爲的script標籤所引用的腳本雖然在加載階段都不會阻塞HTML解析,可是設置了async標誌位的script標籤仍是會在緊接着的執行階段阻塞了HTML解析。而且因爲它是亂序的主,因此它不能知足各個類庫在依賴管理方面的需求。

正所謂一圖勝萬言。常規script標籤,defer標籤和async標籤的加載和執行過程跟HTML解析過程的關係以下圖:

總結

綜上所述,經過調整外部腳本的加載和執行次序來優化首屏渲染速度諸多方案中,爲script標籤添加defer標誌位無疑是最優的。

相關文章
相關標籤/搜索