網(wǎng)站性能優(yōu)化(二)一定要將CSS置于頂部,JS置于底部嗎?

“CSS文件在header中引入,JS文件在body底部引入”,這條建議在前端界幾乎是黃金法則。

首先,筆者聲明,堅決支持這條法則!

只不過,在現(xiàn)代瀏覽器中,尤其是Chrome,已經(jīng)對瀏覽器渲染做了極大的優(yōu)化。哪怕并未遵從這條規(guī)矩,恐怕也不會引發(fā)太大的性能問題。

(注:下面提到的瀏覽器僅限于chrome)

1. 誤區(qū):瀏覽器在解析完整個HTML才會渲染頁面

其實,“為達到更好的用戶體驗,render引擎會力求盡快將內(nèi)容顯示在屏幕上。它不必等到整個 HTML 文檔解析完畢之后,就會開始構(gòu)建呈現(xiàn)樹和設置布局。在不斷接收和處理來自網(wǎng)絡的其余內(nèi)容的同時,render引擎會將部分內(nèi)容解析并顯示出來”(來自文章《瀏覽器的工作原理:新式網(wǎng)絡瀏覽器幕后揭秘》By Tali Garsiel and Paul Irish)。

一般,前端主要關(guān)心首屏(也就是可視區(qū)域內(nèi)的頁面)渲染速度,這也是,為什么要提倡“圖片懶加載”的原因。

2. 誤區(qū):按照順序依次下載CSS和JS文件

其實外部腳本文件和CSS文件是并行下載的。筆者做了個小實驗,如下。
HTML部分:

<html>
<head>
<link rel="stylesheet" href="css.css">
</head>
<body>
...
<script type="application/javascript" src="js1.js"></script>
<script type="application/javascript" src="js2.js"></script>
</body>
</html>

腳本和CSS加載情況:


loading.png

一般資源(如圖片,CSS文件)的獲取和加載不會阻擋當前webkit的渲染過程,但是,某些資源會阻礙主線程渲染(如JS文件),這時,webkit會啟動另外一個線程去遍歷后面的HTML,并收集需要的資源URL,發(fā)起請求。因此,Chrome支持并發(fā)下載資源文件(參考《WebKit技術(shù)內(nèi)幕-朱永盛》)。

有文章將此現(xiàn)象稱為“瀏覽器預解析”:瀏覽器先對HTML代碼做靜態(tài)分析找到外鏈的JS和CSS文件,然后并行下載(但是執(zhí)行順序不變)。PS:IE>=8 及其他主流瀏覽器基本都實現(xiàn)了這個功能。

注意:針對JS文件,并行下載完成后,有序執(zhí)行。

小貼士:

Chrome瀏覽器渲染過程步驟如下(簡單分析):
1. 解析HTML構(gòu)建DOM樹,同時下載腳本,CSS和圖片;
2. CSS文件下載好之后構(gòu)建CSSOM樹;
3. DOM tree和CSSOM tree合并生成Render tree;
4. 做重排(layout)和重繪(paint)工作;
3.小結(jié)

為了提高性能,真正需要關(guān)心的是“首次必須加載哪些CSS和JS?”,盡可能通過異步方式加載那些并不是首屏必需的外部文件。并且,盡量不要加載那些會頻繁操作DOM節(jié)點定位或樣式(尤其是首屏的DOM元素)的JS文件,否則,會導致頁面做多次重排和重繪工作,影響渲染速度。

那么,如何異步加載腳本或者CSS文件?

加載事件一般在window.onload事件中觸發(fā),這時,頁面已經(jīng)完全呈現(xiàn)(相應的資源文件下載完畢),只需要動態(tài)創(chuàng)建<script>標簽或者<link>標簽即可,如下(注意:動態(tài)加載文件也可以利用瀏覽器緩存):

window.onload = function(){
    downloadCSS("a.css");
    downloadJS("b.js");
}
//動態(tài)加載CSS文件
function downloadCSS(url) {
    var elem = document.createElement("link");
    elem.rel = "stylesheet";
    elem.type = "text/css";
    elem.href = url;
    document.body.appendChild(elem);
}
//動態(tài)加載JS文件
function downloadJS(url) {
    var elem = document.createElement("script");
    elem.src = url;
    document.body.appendChild(elem);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容