隨着業務功能的增長,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解析。服務器
爲了達到這個目的,咱們一般會採用如下的方案:網絡
</ body>
標籤前。到這裏,咱們就引出了咱們今天的兩個主角:defer和async。正如上面所說的,添加了這個標誌位的script標籤都會異步加載腳本。這是它們共同的特性,那麼它們之間又有什麼不一樣的地方呢?異步
它們不一樣的地方體如今兩個方面:async
通過查閱資料和親身實踐,咱們能夠有如下的結論:佈局
對於defer標誌位而言:性能
對於async標誌位而言:優化
從上面兩個結論來看,使用了defer和async標誌爲的script標籤所引用的腳本雖然在加載階段都不會阻塞HTML解析,可是設置了async標誌位的script標籤仍是會在緊接着的執行階段阻塞了HTML解析。而且因爲它是亂序的主,因此它不能知足各個類庫在依賴管理方面的需求。
正所謂一圖勝萬言。常規script標籤,defer標籤和async標籤的加載和執行過程跟HTML解析過程的關係以下圖:
綜上所述,經過調整外部腳本的加載和執行次序來優化首屏渲染速度諸多方案中,爲script標籤添加defer標誌位無疑是最優的。