亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

CSS/JS網頁資源阻塞瀏覽器加載的原理是什么

發布時間:2023-03-07 11:21:17 來源:億速云 閱讀:112 作者:iii 欄目:開發技術

本篇內容介紹了“CSS/JS網頁資源阻塞瀏覽器加載的原理是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

正文

一個頁面允許加載的外部資源有很多,常見的有腳本、樣式、字體、圖片和視頻等,對于這些外部資源究竟是如何影響整個頁面的加載和渲染的呢?今天來一探究竟。

  • 如何用 Chrome 定制網絡加載速度?

  • 圖片/視頻/字體會阻塞頁面加載嗎?

  • CSS 是如何阻塞頁面加載的?

  • JS 又是如何阻塞頁面加載的?

  • JS 一定會阻塞 DOM 加載嗎?

  • defer 和 async 是什么?又有何特點?

  • 動態腳本會造成阻塞嗎?

  • 阻塞是怎么和 DOMContentLoaded 與 onload 扯上關系的?

測試前環境準備

測試之前需要對瀏覽器下載資源的速度進行控制,將它重新設置為 50kb/s,操作方式:

  • 打開 Chrome 開發者工具;

  • 在 Network 面板下找到 Disable cache 右側的下拉列表,然后選擇 Add 添加自定義節流配置;

  • 添加一個下載速度為 50kb/s 的配置;

  • 最后在第二步驟中的下拉列表選擇剛剛配置的選項即可;

  • 注意:如果當前選擇的自定義選項被修改了,則需要切換到別的選項再切回來才可生效。

CSS/JS網頁資源阻塞瀏覽器加載的原理是什么

為什么是這個速度?因為如下的一些資源,比如圖片、樣式或者腳本體積都是 50kb 的好幾倍,方便測試。

圖片會造成阻塞嗎?

直接寫個示例來看下結果:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            console.log('DOMContentLoaded')
        })
        window.onload = function() {
            console.log('onload')
        }
    </script>
</head>
<body>
    <h2>我是 h2 標簽</h2>
    <img src="https://xxx.oss-cn-shenzhen.aliyuncs.com/images/flow.png" />
    <h3>我是 h3 標簽</h3>
</body>
</html>

上面這張圖片的大小大概是 200kb,當把網絡下載速度限制成 50kb/s,打開該頁面,可以看到如下結果:當 h2h3 標簽渲染出來且打印了 DOMContentLoaded 的時候,此時圖片還在加載中,這就說明了圖片并不會阻塞 DOM 的加載,更加不會阻塞頁面渲染;當圖片加載完成的時候,會打印 onload,說明圖片延遲了 onload 事件的觸發。
視頻、字體和圖片其實是一樣的,也不會阻塞 DOM 的加載和渲染。

CSS 加載阻塞

同樣的,還是直接用代碼來測試 CSS 加載對頁面阻塞的情況,因為下面代碼加載的 bootstrap.css 是 192kb 的,所以理論上下載它應該需要花費 3 到 4 秒左右。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="stylesheet" />
</head>
<body>
    <h2>我是 h2 標簽</h2>
</body>
</html>

測試過程如下:

  • Elements 面板下,選中 h2 這個標簽,然后按 delete 鍵將它從 DOM 中刪掉,從而模擬首次加載;

  • 刷新瀏覽器,馬上 Elements 面板下就加載出 h2 標簽,繼續加載 3 到 4 秒后(此時正在加載 bootstrap.css),頁面出現 我是 h2 標簽 字樣,此時頁面已經渲染完成。

從而得出結論:

  • bootstrap.css 還沒加載完成,而 DOM 中就已經出現 h2 標簽,說明 CSS 不會阻塞 DOM 的解析;

  • 頁面直到 bootstrap.css 加載完成才出現 h2 里的文案,說明 CSS 會阻塞 DOM 的渲染。

為什么是這個結論呢?試想一下頁面渲染的流程就知道了。瀏覽器首先解析 HTML 生成 DOM 樹,解析 CSS 生成 CSSOM 樹,然后 DOM 樹和 CSSOM 樹進行合成生成渲染樹,通過渲染樹進行布局并且計算每個節點信息,繪制頁面。

CSS/JS網頁資源阻塞瀏覽器加載的原理是什么


可以說解析 DOM 和 解析 CSS 其實是并列進行的,既然是并列進行的,那 CSS 和 DOM 就不會互相影響了,這和結論一相符;另外渲染頁面一定是在得到 CSSOM 樹之后進行的,這和結論二相符。
CSS 一定會阻塞 DOM 的渲染嘛?答案是否定的,當把外鏈樣式放到 <body> 最尾部去加載:

<body>
    <h2>我是 h2 標簽</h2>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="stylesheet" />
</body>

此時刷新瀏覽器,頁面上會馬上顯示出 我是 h2 標簽 字樣,當 3 到 4 秒過后樣式加載完成的時會造成二次渲染,頁面重新渲染出該字樣,這就說明 CSS 阻塞 DOM 的渲染只阻塞定義在 CSS 后面的 DOM。二次渲染會對用戶造成不好的體驗且加重了瀏覽器的負擔,所以這也就是為什么需要把外鏈樣式提前到 <head> 里加載的原因。

CSS 會阻塞后面 JS 的執行嗎?

CSS 阻塞了后面 DOM 的渲染,那它會阻塞 JS 的執行嘛?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="stylesheet" />
</head>
<body>
    <h2>我是 h2 標簽</h2>
    <script>
        console.log('888')
    </script>
</body>
</html>

刷新瀏覽器的時候可以看到,瀏覽器 Console 面板下沒有打印內容,而當樣式加載完成的時候打印了 888,這就說明 CSS 會阻塞定義在其之后 JS 的執行。

為什么會這樣呢?試想一下,如果 JS 里執行的操作需要獲取當前 h2 標簽的樣式,而由于樣式沒加載完成,所以就無法得到想要的結果,從而證明了 CSS 需要阻塞定義在其之后 JS 的執行。

JS 加載阻塞

CSS 會阻塞 DOM 的渲染和阻塞定義在其之后的 JS 的執行,那 JS 加載會對渲染過程造成什么影響呢?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <script src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
    <h2>我是 h2 標簽</h2>
</body>
</html>

首先刪除頁面中已經存在的 h2 標簽(如果存在的話),仔細觀察 Elements 面板,當刷新瀏覽器的時候,一直未加載出 h2 標簽(期間頁面一直白屏),直到 JS 加載完成后,DOM 中才出現,這足以說明了 JS 會阻塞定義在其之后的 DOM 的加載,所以應該將外部 JS 放到 <body> 的最尾部去加載,減少頁面加載白屏時間。

defer 和 async

JS 一定會阻塞定義在其之后的 DOM 的加載嗎?來測試一下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <script async src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
    <h2>我是 h2 標簽</h2>
</body>
</html>

上面這段代碼的測試結果是當頁面中顯示出 h2 標簽的時候,腳本還沒有加載完成,這就說明了 async 腳本不會阻塞 DOM 的加載;同理可以用同樣的方式測試 defer,也會得到這個結論。

現在知道了通過 defer 或者 async 方式加載 JS 的時候,它是不會阻塞 DOM 加載的。知道 deferasync 是什么嗎?它們兩者有什么區別呢?

回答這些疑問之前,先來看下當瀏覽器解析 HTML 遇到 script 標簽的時候會發生什么?

  • 暫停解析 DOM;

  • 執行 script 里的腳本,如果該 script 是外鏈,則會先下載它,下載完成后立刻執行;

  • 執行完成后繼續解析剩余 DOM。

上面這是解析時遇到一個正常的外鏈的情況,正常外鏈的下載和執行都會阻塞頁面解析;而如果外鏈是通過 defer 或者 async 加載的時候又會是如何呢?

CSS/JS網頁資源阻塞瀏覽器加載的原理是什么

defer 特點

  • 對于 deferscript,瀏覽器會繼續解析 html,且同時并行下載腳本,等 DOM 構建完成后,才會開始執行腳本,所以它不會造成阻塞;

  • defer 腳本下載完成后,執行時間一定是 DOMContentLoaded 事件觸發之前執行;

  • 多個 defer 的腳本執行順序嚴格按照定義順序進行,而不是先下載好的先執行;

async 特點

  • 對于 asyncscript,瀏覽器會繼續解析 html,且同時并行下載腳本,一旦腳本下載完成會立刻執行;和 defer 一樣,它在下載的時候也不會造成阻塞,但是如果它下載完成后 DOM 還沒解析完成,則執行腳本的時候是會阻塞解析的;

  • async 腳本的執行 和 DOMContentLoaded 的觸發順序無法明確誰先誰后,因為腳本可能在 DOM 構建完成時還沒下載完,也可能早就下載好了;

  • 多個 async,按照誰先下載完成誰先執行的原則進行,所以當它們之間有順序依賴的時候特別容易出錯。 :::info deferasync 都只能用于外部腳本,如果 script 沒有 src 屬性,則會忽略它們。 :::

動態腳本會造成阻塞嗎?

對于如下這段代碼,當刷新瀏覽器的時候會發現頁面上馬上顯示出 我是 h2 標簽,而過幾秒后才加載完動態插入的腳本,所以可以得出結論:動態插入的腳本不會阻塞頁面解析。

<!-- 省略了部分內容 -->
<script>
    function loadScript(src) {
        let script = document.createElement('script')
        script.src = src
        document.body.append(script)
    }
    loadScript('https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js')
</script>
<h2>我是 h2 標簽</h2>

動態插入的腳本在加載完成后會立即執行,這和 async 一致,所以如果需要保證多個插入的動態腳本的執行順序,則可以設置 script.async = false,此時動態腳本的執行順序將按照插入順序執行和 defer 一樣。

DOMContentLoaded 和 onload

在瀏覽器中加載資源涉及到 2 個事件,分別是 DOMContentLoadedonload,那么它們之間有什么區別呢?

  • onload:當頁面所有資源(包括 CSS、JS、圖片、字體、視頻等)都加載完成才觸發,而且它是綁定到 window 對象上;

  • DOMContentLoaded:當 HTML 已經完成解析,并且構建出了 DOM,但此時外部資源比如樣式和腳本可能還沒加載完成,并且該事件需要綁定到 document 對象上;

一定看到了上面的可能二字,為什么當 DOMContentLoaded 觸發的時候樣式和腳本是可能還沒加載完成呢?

DOMContentLoaded 遇到腳本

當瀏覽器處理一個 HTML 文檔,并在文檔中遇到 <script> 標簽時,就會在繼續構建 DOM 之前運行它。這是一種防范措施,因為腳本可能想要修改 DOM,甚至對其執行 document.write 操作,所以 DOMContentLoaded 必須等待腳本執行結束后才觸發。以下這段代碼驗證了這個結論:當腳本加載完成的時候,Console 面板下才會打印出 DOMContentLoaded

<script>
    document.addEventListener('DOMContentLoaded', () => {
        console.log('DOMContentLoaded')
    })
</script>
<h2>我是 h2 標簽</h2>
<script src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>

那么一定是腳本執行完成后才會觸發 DOMContentLoaded 嘛?答案也是否定的,有兩個例外,對于 async 腳本和動態腳本是不會阻塞 DOMContentLoaded 觸發的。

DOMContentLoaded 遇到樣式

前面已經介紹到 CSS 是不會阻塞 DOM 的解析的,所以理論上 DOMContentLoaded 應該不會等到外部樣式的加載完成后才觸發,這么分析是對的,用下面代碼進行測試一翻就知道了:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
        console.log('DOMContentLoaded')
    })
    </script>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="stylesheet"/>
</head>
<body>
    <h2>我是 h2 標簽</h2>
</body>
</html>

測試結果:當樣式還沒加載完成的時候,就已經打印出 DOMContentLoaded,這和分析的結果是一致的。但是一定是這樣嘛?顯然不一定,這里有個小坑,(基于上面代碼)在樣式后面再加上 <script> 標簽的時候,會發現只有等樣式加載完成了才會打印出 DOMContentLoaded,為什么會這樣呢?正是因為 <script> 會阻塞 DOMContentLoaded 的觸發,所以當外部樣式后面有腳本(**async**** 腳本和動態腳本除外)的時候,外部樣式就會阻塞 **DOMContentLoaded** 的觸發**。

<head>
<!-- 只顯示了部分內容 -->
<link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="stylesheet"/>
<script></script>
</head>

“CSS/JS網頁資源阻塞瀏覽器加載的原理是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阳山县| 怀集县| 曲麻莱县| 张北县| 沈丘县| 福鼎市| 扎鲁特旗| 彭水| 鞍山市| 广宁县| 永善县| 勃利县| 崇仁县| 廉江市| 华池县| 射阳县| 普宁市| 福泉市| 于田县| 平罗县| 永定县| 扎赉特旗| 凤阳县| 四子王旗| 板桥市| 永昌县| 巴青县| 瑞金市| 汉寿县| 垫江县| 永兴县| 荣昌县| 丰镇市| 巴中市| 秀山| 定州市| 平阳县| 安岳县| 田东县| 麻城市| 东安县|