DOMContentLoaded和load的區別

1、概念css

  • DOMContentLoaded

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

  • load

  load 僅用於檢測一個徹底加載的頁面,頁面的html、css、js、圖片等資源都已經加載完以後纔會觸發 load 事件。瀏覽器

2、瀏覽器的一些基本概念數據結構

  • 下載/加載

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

  • 解析

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

  好比下面的代碼:fetch

<!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 文件進行編譯,轉化成相似下面的結構:ui

 

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

  • 遇到 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 樹在合適的時機會被渲染到頁面中。

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

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

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

三、開啓下載線程對文檔中的全部資源按優先級排序下載。

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

  •  發現有外鏈 css 或者外鏈 js,若是是外鏈 js ,則中止解析後續內容,等待該資源下載,下載完後馬上執行。若是是外鏈 css,繼續解析後續內容。

五、解析到 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 結構。

 六、文檔解析完畢,頁面從新渲染。當頁面引用的全部 js 同步代碼執行完畢,觸發 DOMContentLoaded 事件

 七、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>

4、DomContentLoaded 事件的觸發

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

 5、load 事件的觸發

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

相關文章
相關標籤/搜索