DOMContentLoaded和load的區別


一、概念

  • DOMContentLoaded

  當初始的 HTML 文檔被完全加載和解析完成之后,DOMContentLoaded 事件被觸發,而無需等待樣式表、圖像和子框架的完成加載。

  • load

  load 僅用於檢測一個完全加載的頁面,頁面的html、css、js、圖片等資源都已經加載完之后才會觸發 load 事件。

二、瀏覽器的一些基本概念

  • 下載/加載

  瀏覽器將資源下載到本地的過程。

  • 解析

  解析的意思是將一個元素通過一定的方式轉換成另一種形式。
  比如 html 的解析。首先要明確,html 下載到瀏覽器的表現形式就是包含字符串的文件。瀏覽器將 html 文件里面的字符串讀取到內存中,按照 html 規則,對字符串進行取詞編譯,將字符串轉化成另一種易於表達的數據結構。

  比如下面的代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>只有css</title>
  <link rel="stylesheet" href="./index.css" />
</head>
<body>
  <div id="div1"></div>
  <link rel="stylesheet" href="./c1.css" />
  <link rel="stylesheet" href="./c3.css" />
  <script src="http://test.com:9000/mine/load/case2/j1.js
  "></script>
  <link rel="stylesheet" href="./c4.css" />
  <div id="div2"></div>
</body>
</html>

  瀏覽器會對這個 html 文件進行編譯,轉化成類似下面的結構:

 

  瀏覽器會對轉化后的數據結構自上而下進行分析:首先開啟下載線程,對所有的資源進行優先級排序下載(注意,這里僅僅是下載)。同時主線程會對文檔進行解析: 

  • 遇到 script 標簽時,首先阻塞后續內容的解析,同時檢查該script是否已經下載下來,如果已下載,便執行代碼。
  • 遇到 link 標簽時,不會阻塞后續內容的解析(比如 DOM 構建),檢查 link 資源是否已下載,如果已下載,則構建 cssom。
  • 遇到 DOM 標簽時,執行 DOM 構建,將該 DOM 元素添加到文檔樹中。

  ⚠️在 body 中第一個 script 資源下載完成之前,瀏覽器會進行首次渲染,將該 script 標簽前面的 DOM 樹和 CSSOM 合並成一棵 Render 樹,渲染到頁面中。這是頁面從白屏到首次渲染的時間節點

  • DOM 構建

  將文檔中的所有 DOM 元素構建成一個樹型結構,DOM 構建是自上而下進行構建的,會受到 js 執行的干擾。 

  • CSS 構建

  將文檔中的所有CSS資源合並。

  • render 樹

  將 DOM 樹和 CSS 合並成一棵渲染樹,render 樹在合適的時機會被渲染到頁面中。

三、HTML文檔的加載與頁面的首次渲染

1、瀏覽器首先下載該地址所對應的 html 頁面。

2、瀏覽器解析 html 頁面的 DOM 結構。

3、開啟下載線程對文檔中的所有資源按優先級排序下載。

4、主線程繼續解析文檔,到達 head 節點 ,head 里的外部資源是外鏈樣式表和外鏈 js。

  •  發現有外鏈 css 或者外鏈 js,如果是外鏈 js ,則停止解析后續內容,等待該資源下載,下載完后立刻執行。如果是外鏈 css,繼續解析后續內容。

5、解析到 body

  body 里的情況比較多,body 里可能只有 DOM 元素,可能既有 DOM、也有 css、js 等資源,js 資源又有可能異步加載圖片、css、js 等。DOM 結構不同,瀏覽器的解析機制也不同,所以需要分開來討論。

  • 只有 DOM 元素
    • 這種情況比較簡單了,DOM 樹構建完,頁面首次渲染。
  • 有 DOM 元素、外鏈 js
    • 當解析到外鏈 js 的時候,該 js 尚未下載到本地,則 js 之前的 DOM 會被渲染到頁面上,同時 js 會阻止后面 DOM 的構建,即后面的 DOM 節點並不會添加到文檔的 DOM 樹中。所以,js 執行完之前,我們在頁面上看不到該 js 后面的 DOM 元素。
  • 有 DOM 元素、外鏈 css
    • 外鏈 css 不會影響 css 后面的 DOM 構建,但是會阻礙渲染。簡單點說,外鏈 css 加載完之前,頁面還是白屏。
  • 有 DOM 元素、外鏈 js、外鏈 css
    • 外鏈 js 和外鏈 css 的順序會影響頁面渲染,這點尤為重要。當 body 中 js 之前的外鏈 css 未加載完之前,頁面是不會被渲染的。
    • 當body中 js 之前的 外鏈 css 加載完之后,js 之前的 DOM 樹和 css 合並渲染樹,頁面渲染出該 js 之前的 DOM 結構。

 6、文檔解析完畢,頁面重新渲染。當頁面引用的所有 js 同步代碼執行完畢,觸發 DOMContentLoaded 事件

 7、html 文檔中的圖片資源,js 代碼中有異步加載的 css、js 、圖片資源都加載完畢之后,load 事件觸發。

  如下代碼所示:

<body>
  <!-- 白屏 -->
  <div id="div1"></div>
  <!-- 白屏 -->
  <link rel="stylesheet" href="./c1.css" />
  <!-- 白屏 -->
  <link rel="stylesheet" href="./c3.css" />
  <!-- 如果此時 j1.js 尚未下載到本地,則首次渲染,此時的 DOM 樹 只有 div1 ,所以頁面上只會顯示 div1,樣式是 c1.css 和 c3.css 的並集。-->
  <!-- 如果此時 j1.js 已經下載到本地,則先執行 j1.js,頁面不會渲染,所以此時仍然是白屏。-->
  <!--下面的 js 阻塞了 DOM 樹的構建,所以下面的 div2 沒有在文檔的 DOM 樹中。 -->
  <script src="http://test.com:9000/mine/load/case2/j1.js
  "></script>
  <!-- j1.js 執行完畢,繼續 DOM 解析,div2 被構建在文檔 DOM 樹中,此時頁面上有了div2 元素,樣式仍然是 c1.css 和 c3.css 的並集 -->
  <link rel="stylesheet" href="./c4.css" />
  <!-- c4.css 加載完畢,重新構建render樹,樣式變成了 c1.css、c3.css 和 c4.css 的並集 -->
  <div id="div2"></div>
  <script>
  // 利用 performance 統計 load 加載時間。
    window.onload=function(){console.log(performance.timing.loadEventStart - performance.timing.fetchStart);}
  </script>
</body>

四、DomContentLoaded 事件的觸發

   DOMContentLoaded 事件在 html文檔加載完畢,並且 html 所引用的內聯 js、以及外鏈 js 的同步代碼都執行完畢后觸發。

 五、load 事件的觸發

  當頁面 DOM 結構中的 js、css、圖片,以及 js 異步加載的 js、css 、圖片都加載完成之后,才會觸發 load 事件。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM