您好,登錄后才能下訂單哦!
這篇文章主要講解了“js與css的阻塞問題總結”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“js與css的阻塞問題總結”吧!
DOMContentLoaded和load
js 阻塞了什么
css 阻塞了什么
優化
總結
我們先了解兩個事件,有助于后面的分析。
load事件:load 應該僅用于檢測一個完全加載的頁面 當一個資源及其依賴資源已完成加載時,將觸發load事件。也就是說,頁面的html、css、js、圖片等資源都已經加載完之后才會觸發 load 事件。
DOMContentLoaded事件:當初始的 HTML 文檔被完全加載和解析完成之后,DOMContentLoaded 事件被觸發,而無需等待樣式表、圖像和子框架的完成加載。也就是說,DOM 樹已經構建完畢就會觸發 DOMContentLoaded 事件。
因為js在執行的過程中可能會操作DOM,發生回流和重繪,所以GUI渲染線程與JS引擎線程是互斥的。
在解析HTML過程中,如果遇到 script 標簽,渲染線程會暫停渲染過程,將控制權交給 JS 引擎。內聯的js代碼會直接執行,如果是js外部文件,則要下載該js文件,下載完成之后再執行。等 JS 引擎運行完畢,瀏覽器又會把控制權還給渲染線程,繼續 DOM 的解析。
因此,js會阻塞DOM樹的構建。
那么,是否會阻塞頁面的顯示呢?我們用下面的代碼來測試一下。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div>hello world</div> <script> debugger </script> <div>hello world2</div> </body> </html>
可以看到,這個頁面的DOMContentLoaded發生在2.23s,可見js阻塞了DOM樹的構建。但是,頁面上卻幾乎在一瞬間顯示了hello world,說明js不會阻塞位于它之前的dom元素的渲染。
現代瀏覽器為了更好的用戶體驗,渲染引擎將嘗試盡快在屏幕上顯示的內容。它不會等到所有DOM解析完成后才布局渲染樹。而是當js阻塞發生時,會將已經構建好的DOM元素渲染到屏幕上,減少白屏的時間。
這也是為什么我們會將script標簽放到body標簽的底部,因為這樣就不會影響前面的頁面的渲染。
當我們解析 HTML 時遇到 link 標簽或者 style 標簽時,就會計算樣式,構建CSSOM。
css不會阻塞dom樹的構建,但是會阻塞頁面的顯示。我們依然用一個例子來測試:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" type="text/css" href="https://h6.sinaimg.cn/m/weibo-pro/css/chunk-vendors.d6cac585.css"> </head> <body> <div class="woo-spinner-filled">hello world</div> <div>hello world2</div> </body> </html>
使用一個外部css文件,打開Slow 3G模擬比較慢的網速,可以看到,DOMContentLoaded事件觸發只用了30ms,頁面此時依然是空白,而幾乎是loaded事件2.92s發生時,頁面才出現內容。
原因是,瀏覽器在構建 CSSOM 的過程中,不會渲染任何已處理的內容。即便 DOM 已經解析完畢了,只要 CSSOM 不沒構建好,頁面也不會顯示內容。
只有當我們遇到 link 標簽或者 style 標簽時,才會構建CSSOM,所以如果 link 標簽之前有dom元素,當加載css發生阻
<body> <div class="woo-spinner-filled">hello world</div> <link rel="stylesheet" type="text/css" href="https://h6.sinaimg.cn/m/weibo-pro/css/chunk-vendors.d6cac585.css"> <div>hello world2</div> </body>
這樣做會導致一個問題,就是頁面閃爍,在css被加載之前,瀏覽器按照默認樣式渲染 <div class="woo-spinner-filled">hello world</div>,當css加載完成,會為該div計算新的樣式,重新渲染,出現閃爍的效果。
為了避免頁面閃爍,通常 link 標簽都放在head中。
css會不會阻塞后面js執行?答案是會!
JS 的作用在于修改,它幫助我們修改網頁的方方面面:內容、樣式以及它如何響應用戶交互。這“方方面面”的修改,本質上都是對 DOM 和 CSSDOM 進行修改。當在JS中訪問了CSSDOM中某個元素的樣式,那么這時候就需要等待這個樣式被下載完成才能繼續往下執行JS腳本。
運行下面這個例子,就會發現等css加載完成后,才會在控制臺打印“this is a test”。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" type="text/css" href="https://h6.sinaimg.cn/m/weibo-pro/css/chunk-vendors.d6cac585.css"> </head> <body> <div class="woo-spinner-filled">hello world</div> <div>hello world2</div> <script> console.log('this is a test') </script> </body> </html>
使用內聯 JavaScript 和 CSS,這樣獲取到 HTML 文件之后就可以直接開始渲染流程了。
并不是所有的場合都適合內聯,那么還可以盡量減少文件大小,比如通過 webpack 等構建工具刪除無用代碼、壓縮 css、JavaScript 文件的體積;并且啟用 CDN 加快文件的下載速度。
對于大的 CSS 文件,可以通過媒體查詢屬性,將其拆分為多個不同用途的 CSS 文件,這樣只有在特定的場景下才會加載特定的 CSS 文件。
如果 JavaScript 文件中沒有操作 DOM 相關代碼,就可以將該 JavaScript 腳本設置為異步加載,通過 async 或 defer 來標記代碼。
<script src="index.js"></script> //瀏覽器必須等待 index.js 加載和執行完畢才能去做其它事情。 <script async src="index.js"></script> //index.js 的加載是異步的,加載時不會阻塞瀏覽器做任何其它的事情。 //當它加載結束,JS 腳本會立即執行。 <script defer src="index.js"></script> //JS 的加載是異步的,執行是被推遲的。 //使用了 defer 標記的腳本文件,會等整個文檔解析完成,在 DOMContentLoaded 事件觸發之前執行
感謝各位的閱讀,以上就是“js與css的阻塞問題總結”的內容了,經過本文的學習后,相信大家對js與css的阻塞問題總結這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。