網頁 head 標籤中的 JS 和 CSS,哪種文件放在前面,哪种放在後面比較好?
玉伯和克軍的文章主要說了資源載入順序的問題,我補充一下針對問題的回答。順序一般是:
1. 個別特殊JS,比如用於調試的基礎腳本(部署時未必有)、性能日誌之類,必須放在盡量最前的位置。
2. 外部樣式表(link[rel=stylesheet])3. 本頁樣式(style)4. 基礎庫,比如loader,各種shim/polyfill,jQuery之類的
注意,有些開發者從性能優化的角度傾向於加defer或者放到頁面的最底部。不過不是所有的腳本都能這樣做。比如html5-shim腳本必須在body之前載入。再如history api的兼容實現等都不應defer,因為你不能確保用戶在頁面ready之前沒有back/forward動作。再如jQuery,defer是可以,但也意味著你所有依賴jQuery的功能都需要defer,考慮到這些靜態文件通常都是有緩存的,所以不defer也未必不是一個可以接受的折衷。5. 少量本頁script以上。跟著 @歐雷 的指引,在張克軍的博文中提到了另一篇深入探討的文章:http://lifesinger.wordpress.com/2012/02/03/performance-impact-of-js-css-loading-order/
------------------------ 由於 http://wordpress.com 這個網站「並不存在」,以下內容是通過 Pocket(原 ReadItLater)服務捏造而來,請看官自辨 -----------------------
JS 和 CSS 的位置對其他資源載入順序的影響克軍做了一系列測試:js和css的順序關係,給出了現象和結論,但未給出原因。JS 和 CSS 在頁面中的位置,會影響其他資源(指 img 等非 js 和 css 資源)的載入順序,究其原因,有三個值得注意的點:- JS 有可能會修改 DOM. 典型的,可能會有 document.write. 這意味著,在當前 JS 載入和執行完成前,後續所有資源的下載有可能是沒必要的。這是 JS 阻塞後續資源下載的根本原因。
- JS 的執行有可能依賴最新樣式。比如,可能會有 var width = $("#id").width(). 這意味著,JS 代碼在執行前,瀏覽器必須保證在此 JS 之前的所有 css(無論外鏈還是內嵌)都已下載和解析完成。這是 CSS 阻塞後續 JS 執行的根本原因。
- 現代瀏覽器很聰明,會進行 prefetch 優化。性能是如此重要,現代瀏覽器在 競爭中,在 UI update 線程之外,還會開啟另一個線程,對後續 JS 和 CSS 提前下載(注意,僅提前下載,並不執行)。有了 prefetch 優化,這意味著,在不存在任何阻塞的情況下,理論上 JS 和 CSS 的下載時機都非常優先,和位置無關。
以上三點可簡述為三條基本定律:
- 定律一:資源是否下載依賴 JS 執行結果。
- 定律二:JS 執行依賴 CSS 最新渲染。
- 定律三:現代瀏覽器存在 prefetch 優化。
有了這三條定律,再來看克軍的測試,就很清晰了:
a,b – head里出現外聯js,無論如何放,css文件都不能和body里的請求並行
根據定律一和定律三,可以知道上面的結論不夠正確。比如:
& & & & & & & & & 在 Chrome 下的瀑布圖是:黃色條是 js 的,可以看出 img 的延時下載是由定律一決定的。定律三則決定了所有 js/css 都是並行開始下載的。在 Firefox 10 下,prefetch 非常強悍,對 img 也會預載入,瀑布圖如下:調整一下 sleep 時間,還可以觀察到定律二的威力:&
& & & & & & & & & 瀑布圖立刻發生了變化:因為定律一,決定 img 的下載在 js 執行後。又因為定律二,決定 js 的執行在第一個 css 後。於是最後在瀑布圖上體現出來,就是 img 的下載在第一個 css 後。再來看克軍的第二個結論:c – head里的內聯js只要在所有外聯css前面,css文件可以和body里的請求並行(圖2)
d – head里的內聯js只要在任一外聯css後面,css文件就不能和body里的請求並行(圖1)這個是定律二的威力。結論 c 是正確的,因為沒有 css 會影響 js 的執行。結論 d 則不夠正確。img 等其他資源,會在 js 前面的 css 下載完成後,以及 js 執行後,立刻開始下載。與頭部中,js 位置之後的 css 沒關係。克軍的其他結論都是對的,不多說。注意1:Firefox 10 的 prefetch 有點奇怪,有時會對 img 進行 prefetch,有時則不會。有興趣的可以進一步尋找規律。 注意2:上面的三個定律,是黑盒猜測,有興趣的可以去閱讀瀏覽器的源碼,應該能找到更深層次的原因。注意3:本文沒有考慮 defer, async 屬性的影響,這是另一個故事。
瀏覽器在迅速發展,很多總結,特別是書籍上的,很難與時俱進。大家應該像克軍學習,多測試,多發現,這樣得來的知識,才不會過時。這篇博客的總結,也肯定在未來甚至就在現在,已經存在錯誤。這些都無所謂,關鍵是要懂得測試的方法和分析的思路,有了「漁」,才能更好地探求和擁有「魚」。head 內的 JavaScript 需要執行結束才開始渲染 body,所以盡量不要將 JS 文件放在 head 內。可以選擇在 document complete 時,或者特定區塊後引入和執行 JavaScript。
而 CSS 應當寫在 head 中,以避免頁面元素由於樣式確實造成瞬間的白頁或者給用戶閃爍感。@吳釗 說的是對的,以色列的開發人員加希尓在翻閱了現代瀏覽器內核源碼以後,寫了一文&<現代瀏覽器工作原理&>。瀏覽器中分主副解析引擎。head中引入的腳本可以直接柱塞主解析引擎的解析工作(比如某個瞬間我們發現網頁後面一片空白),如果這些腳本中有操作dom的函數,那麼這些函數不會執行,會被標識為延時狀態,等dom載入完後才會追趕執行。如果腳本中有可執行的函數,那麼dom的解析也會被柱塞,瀏覽器轉而要先去執行腳本。腳本執行完畢後,dom解析才繼續。
為了避免head引入的腳本柱塞主解析引擎對dom的解析工作,更快的載入dom並渲染出來,一般的原則是,樣式放在前面,腳本放在最後面。遵從先解析再渲染再執行script這個順序。yahoo21條中也有提及。參考:http://blog.csdn.net/uohzoaix/article/details/7299054http://www.huilinwang.com/blog/post/87.html.html
不同意因為js腳本會阻塞dom構建的原因,而將js腳本放在末尾。
Edit fiddle - JSFiddle
就算放在末尾了,也一樣會阻塞dom的構建。
推薦閱讀:
※2016年前端技術將會呈現怎樣的局勢?全棧工程師是不是前端的一個趨勢?
※web移動前端有哪些優化方案?
※如何分析頁面性能?
※公司官網的圖片用什麼格式比較好?
TAG:前端開發 | CSS | JavaScript | HTML5 | 前端性能優化 |