能大家都知道,js執行會阻塞DOM樹的解析和渲染,那么css加載會阻塞DOM樹的解析和渲染嗎?接下來,我們就一起來分析一下。
那么為什么會出現上面的現象呢?我們從瀏覽器的渲染過程來解析下。
不同的瀏覽器使用的內核不同,所以他們的渲染過程也是不一樣的。目前主要有兩個:
webkit渲染過程
Gecko渲染過程
從上面兩個流程圖我們可以看出來,瀏覽器渲染的流程如下:
從流程我們可以看出來
對于瀏覽器來說,頁面加載主要有兩個事件,一個是DOMContentLoaded,另一個是onLoad。而onLoad沒什么好說的,就是等待頁面的所有資源都加載完成才會觸發,這些資源包括css、js、圖片視頻等。
而DOMContentLoaded,顧名思義,就是當頁面的內容解析完成后,則觸發該事件。那么,正如我們上面討論過的,css會阻塞Dom渲染和js執行,而js會阻塞Dom解析。那么我們可以做出這樣的假設
我們先對第一種情況做測試:
<!DOCTYPE html> <html lang="en"> <head> <title>css阻塞</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script> document.addEventListener('DOMContentLoaded', function() { console.log('DOMContentLoaded'); }) </script> <link rel="stylesheet"> </head> <body> </body> </html>
實驗結果如下圖:
從動圖我們可以看出來,css還未加載完,就已經觸發了DOMContentLoaded事件了。因為css后面沒有任何js代碼。
接下來我們對第二種情況做測試,很簡單,就在css后面加一行代碼就行了
<!DOCTYPE html> <html lang="en"> <head> <title>css阻塞</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script> document.addEventListener('DOMContentLoaded', function() { console.log('DOMContentLoaded'); }) </script> <link rel="stylesheet"> <script> console.log('到我了沒'); </script> </head> <body> </body> </html>
實驗結果如下圖:
我們可以看到,只有在css加載完成后,才會觸發DOMContentLoaded事件。因此,我們可以得出結論:
由上所述,我們可以得出以下結論:
因此,為了避免讓用戶看到長時間的白屏時間,我們應該盡可能的提高css加載速度,比如可以使用以下幾種方法:
文由 ChatMoney團隊出品
在我們開發網站應用時,我們可能會遇到腳本加載失敗的情況,導致腳本加載失敗的原因有很多,比如用戶的網絡問題、終端設備問題、用戶瀏覽器版本等諸多因素。
在 JavaScript 中,我們可以創建一個監聽來監聽腳本加載失敗的情況,然后針對加載失敗的腳本進行重新加載。
重新加載的方案,一般是通過更換域名來解決。我們給每個腳本添加一個映射關系表,用來在加載失敗時匹配新的域名進行重試。
具體的解決方案,下面我一步一步講解,另外希望大家可以仔細閱讀注釋中的內容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>腳本加載失敗如何重試</title>
<script>
window.addEventListener(
"error", // 監聽全局錯誤
function (e) {
console.log(e);
},
true // 由于腳本加載失敗不會冒泡,所以我們要在捕獲階段進行監聽
);
</script>
</head>
<body>
<script src="https://www.zowlsat.com/api/1.js"></script>
<script src="https://www.qqqqqqq.com/api/2.js"></script>
<script src="https://www.zowlsat.com/api/3.js"></script>
</body>
</html>
此時我們可以在瀏覽器控制臺看到以下效果
但是這個監聽方法會監聽到很多其他的錯誤,我們只需要監聽腳本加載失敗的錯誤,所以我們要通過這個監聽事件的參數 e 來判斷了
根據上圖我們可以發現,普通錯誤的類型是 ErrorEvent,而腳本加載失敗的類型是 Event,并且他的 target 會指向 script 標簽,所以我們根據這個區別過濾掉其他的錯誤,這樣剩下的情況才是我們需要處理的。
window.addEventListener(
"error",
function (e) {
if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return;
console.log(e);
},
true
);
接下來就是如何來實現重新加載,我們先給需要重新加載的域名建立一個映射關系,用于替換映射關系表中的域名。然后就是挨個匹配,當還是加載失敗時繼續匹配下一個,直到成功為止。
const domainList = ["www.aaaaa.com", "www.bbbbb.com", "www.zowlsat.com"];
const retry = {};
window.addEventListener(
"error",
function (e) {
if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return;
// 創建一個URL對象
const url = new URL(e.target.src);
// 獲取文件路徑
const key = url.pathname;
// 假如映射表中沒有這個文件路徑,那么就初始化一個映射鍵
if (!(key in retry)) {
retry[key] = 0;
}
// 假如匹配完整個映射表都沒重新加載成功,則放棄
const index = retry[key];
if (index >= domainList.length) {
return;
}
// 獲取新的完整路徑
const domain = domainList[index];
// 替換域名
url.host = domain;
// 創建新的script標簽
const script = document.createElement("script");
script.src = url.toString();
// 將新的script標簽追加到加載失敗的script標簽之前
document.body.insertBefore(script, e.target);
retry[key]++;
},
true // 由于腳本加載失敗不會冒泡,所以我們要在捕獲階段進行監聽
);
到此為止,我們功能已經基本實現,效果如下圖
但是有一個很關鍵的問題,就是假如我 2.js 這個文件中的內容,在 3.js 中要使用,那這樣的話,2.js 就必須加載到 3.js 之前,否則就會報錯。此時,我們就需要在 2.js 加載失敗時,阻塞瀏覽器的解析,知道重新加載完成或者放棄重新加載時,再繼續渲染之后的內容。
那這樣的話我們該怎么做呢?
其實很簡單,在我們入門 js 時就學到過一個知識點,就是使用document.write
document.write這個方法在解析期間使用的話,會阻塞瀏覽器的解析,而我們現在就是需要阻塞瀏覽器解析,那此時我們只需要將創建 script 標簽的方法更換為document.write方法即可。
修改之后的代碼如下:
const domainList = ["www.aaaaa.com", "www.bbbbb.com", "www.zowlsat.com"];
const retry = {};
window.addEventListener(
"error",
function (e) {
if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return;
const url = new URL(e.target.src);
const key = url.pathname;
if (!(key in retry)) {
retry[key] = 0;
}
const index = retry[key];
if (index >= domainList.length) {
return;
}
const domain = domainList[index];
url.host = domain;
// 此處加上轉譯是因為防止編譯器識別script標簽為結束標簽報錯
document.write(`\<script src="${url.toString()}">\<\/script>`);
// const script = document.createElement("script");
// script.src = url.toString();
// document.body.insertBefore(script, e.target);
retry[key]++;
},
true
);
現在我們再打開控制臺查看,現在js文件按它原來的順序執行了,這樣既不會改變原有的代碼邏輯,又可以在可控范圍內進行重新加載。
效果如下圖:
以上是簡單實現了一個js文件重新加載錯誤的方案,其實這個方案也可以運用到其他很多類型的文件,不限于js文件。
然后我們還需要更加細化這個方法的話,我們可能還需要考慮到這個script標簽是否帶有async、defer等屬性,還有諸多需要考慮的點,但是沿著這個方向解決的話,大體是沒有問題的。
本文由ChatMoney團隊出品,ChatMoney專注于AI應用落地與變現,我們提供全套、持續更新的AI源碼系統與可執行的變現方案,致力于幫助更多人利用AI來變現,歡迎進入ChatMoney獲取更多AI變現方案!
SS加載確實有可能阻塞頁面加載,但這并非絕對,具體取決于CSS的加載方式、應用位置以及瀏覽器的渲染機制。在了解CSS加載如何影響頁面加載之前,我們先要明白瀏覽器渲染頁面的基本流程。
瀏覽器在加載網頁時,會按照從上到下的順序解析HTML文檔。當瀏覽器遇到`<link>`標簽引用外部CSS文件時,它會停止HTML的解析,轉而加載并應用這個CSS文件。這個過程被稱為CSS阻塞。因此,如果這個CSS文件很大或者加載速度很慢,用戶可能會看到一個空白頁面,直到CSS文件完全加載并應用。
然而,有幾種方法可以避免或減輕CSS加載對頁面加載的阻塞:
此外,值得注意的是,現代瀏覽器通常具有一些優化機制,如并行下載、緩存等,這些都可以幫助減少CSS加載對頁面加載的影響。
總的來說,CSS加載確實有可能阻塞頁面加載,但通過一些優化策略和技術,我們可以減輕或避免這種阻塞。選擇哪種策略取決于你的具體需求和約束。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。