一個微信面試題引起的血案 --[譯] 什麼阻塞了 DOM?

譯者注:昨天一篇工做僅一年的前端工程師面試幾個大廠的文章 (1月前端面試記) 在掘金火爆起來。一方面你們以爲做者太厲害了,工做近一年,能力居然這麼強(大叔我表示慚愧),另外一方面幾個微信面試題引發不少討論。其中我比較感興趣的一個題目是關於JavaScript和CSS阻塞DOM的。老實話講,我之前也沒太關注過,與其哀嘆本身研究的不夠深刻,不如咱們去學習彌補一下吧。這篇文章是我今天讀到的,感受不錯,翻譯一下給你們共享。javascript

原文地址:www.keycdn.com/blog/blocki…
原文做者:BRIAN JACKSONcss


當咱們談到web性能或者優化頁面級別的速度時,很是重要的一點是要理解HTML和一個頁面是如何在瀏覽器中構造的,這樣你才能找到因爲渲染阻塞致使的頁面加載延遲。在這篇文章中,咱們會深刻了解是 什麼阻塞了DOM 以及你應該怎樣避免這種狀況。html

什麼是DOM?

DOM是Document Object Model(文檔對象模型)的縮寫。它是爲HTML和XML定義的一個編程接口,提供了文檔的結構化表示(節點樹狀結構),同時也規定了使用腳本編程語言(例如JavaScript)應該如何訪問以及操做DOM。這樣一個節點樹狀結構是由不一樣的元素、父節點、子節點、兄弟節點等構成,它們彼此都有層級化的關係。下圖是一個HTML DOM的例子:前端

HTML DOM

用人話描述DOM

簡單的講,當你使用一個相似Chrome開發者工具的東東時,你能夠看到一個可視化的DOM。你的HTML並非DOM,但Chrome開發者工具爲你展示了一個通過HTML或JavaScript加工以後的DOM。因此你能夠把DOM理解成解析後的HTML。java

Chrome開發者工具中體現的DOM

什麼在阻塞DOM?

當咱們分析頁面速度時,咱們總要考慮什麼阻塞了DOM致使咱們的頁面加載出現延遲。這些阻塞因素咱們能夠叫作 阻塞渲染的資源 ,例如 HTML、CSS(也包括web font)和 JavaScript。jquery

要查看什麼阻塞了DOM的最簡單的方法之一就是使用 Chrome開發者工具 (Chrome DevTools) 和Google的 PageSpeed Insight。在下面的例子中,咱們使用了最新的Chrome開發者工具 (能夠經過 Chrome Canary 得到)。web

  1. 在Chrome中啓動開發者工具
    • Windows:F12 或者 Ctrl + Shift + I
    • Mac: Cmd + Opt + I
  2. 切換到 Network (網絡)面板,刷新頁面( Win: Ctrl + R, Mac: Cmd + R
  3. 如今你會看到一個加載時間瀑布圖。這裏有兩個值得咱們關注的東東:第一個是 DOMContentLoaded 是384ms(譯者注:原文如此,看圖的話應該是281ms),第二個就是瀑布圖中的在藍線以前的綠色部分(譯者注:原圖有點問題,藍線看起來是紫色的)

咱們知道CSS和JavaScript都是阻塞渲染的資源,它們都會在藍色的DOMContent以前加載。請注意,圖像是不會阻塞渲染的 ,因此若是有圖像落在藍線以前或之上你能夠放心的忽略掉,固然優化圖像也是很重要的一項工做。在這個例子裏面,咱們能夠看到 style.cssjquery.min.js 都是阻塞渲染的資源。面試

Chrome開發者工具的網絡面板中的加載時間瀑布圖

你一樣能夠經過 Google PageSpeed Insightsdevelopers.google.com/speed/pages… 工具來驗證咱們上面的結論。下圖中顯示這兩個文件的確是阻塞渲染的。chrome

Google PageSpeed Insights

咱們下面要學習的是如何 經過優化關鍵渲染路徑來避免CSS和JavaScript阻塞DOM 。儘管HTML也算是一個阻塞渲染的資源(譯者注:記住HTML不是DOM),但DOM是能夠增量構建的(譯者注:因此優化的是CSS和JavaScript,而不是HTML)。npm

注意,咱們無需追求在 Google PageSpeed Insights100/100。例如,若是你連接引用了Google的web字體,那麼不管你作什麼,這個外部的 fonts.googleapis.com 樣式都始終會是一個阻塞渲染的資源。重要的是當你在處理有着10+個阻塞渲染資源的一個大型站點時,要理解清楚什麼致使了延遲,有什麼樣的策略可使這些資源能夠更有效率的加載。

CSS

非渲染阻塞的CSS

若是你追求一個徹底沒有阻塞的CSS,那麼你的惟一選項就是:在HTML中內聯嵌入你的CSS。你能夠把須要初始渲染的CSS,通常來說就是第一屏的樣式,直接放在 HEAD 裏面的 <style></style> 中,而後剩下的CSS放在 </body> 以前。這樣作能夠徹底避免CSS阻塞渲染。

有幾個能夠輔助你完成內聯樣式嵌入的自動化插件

你固然也可使用JavaScript來加載CSS,可是這樣作會致使頁面在加載結束時重繪,所以這個選項對於網站訪問者來講不必定會很理想。

在Chrome開發者工具中能夠看到,咱們作完內聯樣式優化以後的版本中 DOMContentLoaded 減小到了 278ms

內聯優化後的版本

如今咱們再去 Google PageSpeed Insights 測試,會發現CSS已不是阻塞渲染的資源了。

內聯優化後的測試

固然這很不錯,但一切取決於你的站點實際狀況。大多數站點並不想內聯嵌入全部的CSS,由於CSS的內容多少直接且顯著的影響了頁面下載的大小。對於小型站點或者就是個 Landing Page ,這種狀況下內聯嵌入CSS能夠是一個不錯的選項,若是你真的想徹底避免CSS阻塞渲染的話。

咱們的CSS建議

即便在咱們本身的KeyCDN主頁上,咱們也有一個阻塞渲染的CSS。可是,咱們作了其餘一些事情來優化CSS的加載時間,下面是咱們的建議:

  1. 正確的調用你的CSS文件 (譯者注:原文如此,感受應該是位置或時機?)
  2. 使用 media queries (媒體查詢) 來標記某些CSS爲非阻塞資源 (譯者注: 好比 <link href="other.css" rel="stylesheet" media="(min-width: 40em)"> 這樣能夠在其餘屏幕尺寸加載時就不用加載這個css了)
  3. 減小CSS的數量(儘量放到一個CSS文件中)
  4. Minify CSS文件(刪除多餘的空格、字符、註釋等)
  5. 儘量的減小樣式數量(譯者注:和第三條不一樣,是減小樣式數量,不是文件數量)

一些用於最小化(Minify)CSS的工具

JavaScript

非渲染阻塞的JavaScript

有一些關於JavaScript的最佳實踐須要牢記在心:

  1. 把腳本放在頁面尾部 </body> 以前的位置
  2. 使用async或defer指令來避免阻塞渲染

異步加載JavaScript

async 容許腳本在後臺下載,所以是無阻塞的。可是當下載完成的時刻,渲染又會阻塞了,這是由於腳本執行了。當腳本執行完畢,渲染又恢復了。

<script async src="foobar.js"></script>複製代碼

延遲加載JavaScript

defer 指令作的事情和 async 基本同樣,區別點在於 defer 是嚴格要求腳本的執行順序必須和在HTML中標記的順序同樣。因此說,可能存在一種狀況,當一些腳本已經下載完畢,這些腳本不會當即執行,它們會等待其餘腳本下載完成,由於那些腳本在HTML中出如今它們以前。

Patrick Sexton寫了一篇很是好的博文: 如何延遲加載JavaScript

除去上面兩條,咱們對於JavaScript的另外3條建議是:

  1. 減小JavaScript的數量(儘可能整合成一個JS文件)
  2. Minify(最小化)JavaScript
  3. 若是JavaScript很小的話,能夠內聯嵌入

用於最小化JavaScript的自動化任務插件

  • Grunt:grunt-contrib-uglify
  • Gulp:gulp-uglify

    經過把咱們的JavaScript移動到頁面尾部,以及使用 async 指令以後,咱們把 DOMContentLoaded 顯著的減小到了 144ms。咱們能夠看到 jquery.min.js 文件如今出如今了DOM的藍線以後了。

JavaScript優化後在Chrome開發者工具中的表現

那麼在 Google PageSpeed Insights 中一樣的,因爲咱們已經異步加載了JavaScript,因此這一項的扣分不存在了,咱們達成了 100/100

達成100分

Web Fonts

Web Fonts(Web字體)也被視爲一種阻塞渲染的資源,由於它們是經過CSS加載的。你有兩個選擇:阻塞渲染或者延遲重繪(這種狀況你須要處理 FOUT)。舉個例子,在Chrome(36以上版本),Opera(23以上版本)和Firefox中有一個 three-second timeout,在超時後,fall-back字體會被使用。

一樣的咱們有幾個關於加載字體和優化關鍵渲染路徑的小建議:

  1. 使用Web Font加載器或者字體加載API
  2. 使用內聯嵌入優化字體加載
  3. 使用例如localStorage等存儲方法

關於更多深刻的加載Web Fonts、如何避免渲染阻塞以及FOUT/FOIT等能夠查看這篇博文:
analyzing web font performance

小總結

咱們但願到這裏你能夠對阻塞DOM、DOM樹是如何構建的,爲什麼會被CSS和JavaScript阻塞等問題有了一些瞭解。請再次記住不要追求 Google PageSpeed Insights100/100,重要的是理解你的渲染阻塞資源是如何阻塞DOM的以及你會怎樣正確的優化使得頁面的加載變快。


本文對你有幫助?歡迎掃碼加入前端學習小組微信羣:

相關文章
相關標籤/搜索