自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

通過Performance面板驗證瀏覽器資源加載與渲染機制

系統(tǒng) 瀏覽器
文檔對象模型(Document Object Model,簡稱 DOM),是 W3C 組織推薦的處理可擴展置標語言的標準編程接口。DOM 把整個頁面映射為一個多層的節(jié)點結構,HTML 或 XML 頁面中的每個組成部分都是某種類型的節(jié)點,這些節(jié)點又包含著不同類型的數(shù)據(jù)。

前言

一個網(wǎng)頁的核心由HTML、CSS和JavaScript組成,三者協(xié)同工作以呈現(xiàn)內(nèi)容并實現(xiàn)交互。但瀏覽器如何解析這些資源?加載順序如何影響用戶體驗?讀完本本文你將徹底弄懂以下核心知識

  1. 為什么需要生成DOM樹?
  2. CSS是否會阻塞HTML解析?是否阻塞頁面渲染?
  3. JavaScript是否會阻塞HTML解析?
  4. JavaScript的異步加載機制如何影響解析過程?
  5. 如何通過performance面板驗證以上觀點

認識DOM

文檔對象模型(Document Object Model,簡稱 DOM),是 W3C 組織推薦的處理可擴展置標語言的標準編程接口。DOM 把整個頁面映射為一個多層的節(jié)點結構,HTML 或 XML 頁面中的每個組成部分都是某種類型的節(jié)點,這些節(jié)點又包含著不同類型的數(shù)據(jù)。

W3C DOM 由以下三部分組成:

  • 核心 DOM - 針對任何結構化文檔的標準模型
  • XML DOM - 針對 XML 文檔的標準模型
  • HTML DOM - 針對 HTML 文檔的標準模型

如果覺得這樣介紹不夠直觀,可以看下這張圖:

圖片圖片

各個dom節(jié)點組合起來就形成了一個樹狀結構,所以我們通常稱之為DOM樹。

為什么需要DOM樹?

  • 結構化數(shù)據(jù):將HTML標簽(如<div>、<p>)和文本內(nèi)容轉化為節(jié)點對象,以樹形結構表示標簽的父子嵌套關系。
  • JavaScript動態(tài)操作的基礎:這一過程解決了原生HTML文本的局限性,允許JavaScript通過屬性與方法直接操作節(jié)點。
  • 渲染過程的核心輸入:DOM樹提供內(nèi)容結構,CSSOM樹提供樣式規(guī)則,兩者結合生成渲染樹(Render Tree),決定頁面元素的可見性與布局。
  • 安全性:DOM解析階段會過濾惡意內(nèi)容。

DOM 是瀏覽器對頁面的內(nèi)部表示,也是 Web 開發(fā)人員可以通過 JavaScript 交互的數(shù)據(jù)結構和 API。

解析HTML

網(wǎng)絡線程獲取HTML文件后,瀏覽器才會開始進行解析處理生成DOM樹。

圖片圖片

在這個過程中每個HTML標簽都會被瀏覽器解析成文檔對象,并且所有的文檔對象最終都會被掛在document

比如:

圖片圖片

并且為了提高解析效率,在解析之前,瀏覽器會啟動一個預解析的線程,提前去下載文檔中的外部CSS文件和外部JS文件。

解析CSS

在構建DOM的過程中,如果遇到link標簽,當把它插入到DOM樹上后,此時如果外部的CSS文件還沒有下載完,主線程也不會停下來等待,因為下載和解析CSS的工作是在預解析線程中進行的,所以CSS并不會阻塞html的解析。

解析html的目的是為了生成DOM樹,而解析CSS的目的同樣是為了生成CSSOM樹,兩者都是為了轉換成瀏覽器能夠理解的結構,也可以方便javascript的訪問。

我們可以通過document.styleSheets來查看它的結構:

圖片圖片

CSSOM結構主要是為了給JavaScript提供操作樣式表的能力,以及提供基礎的樣式信息。

大體上來說,CSSOM是一個建立在web頁面上的 CSS 樣式的映射,它和DOM類似,但是只針對CSS而不是HTML,瀏覽器會將DOM和CSSOM結合生成渲染樹。

CSS是否會阻塞渲染?

雖然CSS并不會阻塞html的解析,但由于渲染樹的生成需要CSSOM的參與,所以CSS是會阻塞頁面渲染的

真的原因是,如果瀏覽器在CSS檢查之前展示了頁面,那么每個頁面都是沒有樣式的,等一會之后又突然有了樣式,整個頁面的體驗就會很差。由于CSSOM被用作創(chuàng)建渲染樹,那么如果不能高效的利用CSS會導致白屏時間的增加

解析javascript

在構建DOM的過程中,如果遇到script,在默認情況下主線程會停止對html的解析,轉而等待 JS 文件下載好,并將全局代碼解析執(zhí)行完成后,才會繼續(xù)解析html。這是因為 JS 代碼的執(zhí)行過程可能會修改當前的 DOM 樹,所以 DOM 樹的生成必須暫停。這就是 JS 會阻塞 HTML 解析的根本原因。

在html5中對script新增了兩個屬性可用于異步加載腳本,設置不同的屬性對解析HTML文檔也有很大的影響。

異步加載

圖片

這里我們要討論的不僅僅是asyncdefer,還有type=module

默認情況
  • 在默認情況下,script 標簽在請求和執(zhí)行的時候都會阻塞文檔解析
defer

延遲腳本執(zhí)行:帶有defer屬性的腳本,加載不會阻塞頁面的解析和渲染過程,瀏覽器可以繼續(xù)解析頁面的其余部分,當整個文檔完成解析后,在觸發(fā)DOMContentLoaded事件之前執(zhí)行這些腳本。

順序執(zhí)行:帶有defer屬性的腳本,盡管是異步加載的,但是它們之間會保持順序執(zhí)行。

async

非阻塞加載:帶有async屬性的腳本加載是異步的,不會阻塞HTML文檔的解析,瀏覽器可以繼續(xù)向下解析和渲染。不過,當腳本加載完成后,會立即執(zhí)行腳本內(nèi)的代碼,此時如果HTML還沒有解析完成,則會暫停對html的解析,從而阻塞頁面渲染。但如果當腳本加載完準備執(zhí)行之前,html已經(jīng)解析完成,此時也不會阻塞頁面渲染。

執(zhí)行不可控:帶有async屬性的腳本,執(zhí)行是不可控的,因為無法確定腳本的下載速度與腳本內(nèi)容的執(zhí)行速度,如果存在多個script async時,他們之間的執(zhí)行的順序也是不可控的,完全取決于各自的下載速度,誰先下載完成就先執(zhí)行誰。

module

非阻塞加載:帶有type="module"的腳本加載是異步的,這類標簽視為ES6模塊來處理,而ES6模塊是設計為異步加載的,當瀏覽器遇到此類標簽時,會開始異步下載改模塊及其依賴項,不會暫停頁面的解析和渲染工作,當HTML文檔被解析完成后,會在觸發(fā)DOMContentLoaded事件之前執(zhí)行這些腳本。所以它的表現(xiàn)有點類似defer。

模塊化支持:帶有type="module"的腳本會自動分割成不同的模塊,并且相互之間作用域是隔離的,瀏覽器會自動加載這些模塊,無需手動管理依賴關系。

支持靜態(tài)導入和動態(tài)導入:可以使用import語句靜態(tài)地導入其它模塊,這些導入的模塊加載時自動解析和執(zhí)行。還可以使用import()函數(shù)動態(tài)地導入模塊,根據(jù)需要在運行時加載模塊,進一步控制模塊的加載和執(zhí)行時機。

module && async

表現(xiàn)類似async

通過performance驗證

實驗代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./a.css" />
    <script>
        console.log('【readystatechange】', document.readyState)
        document.addEventListener('readystatechange', (e) => {
            console.log('【readystatechange】', document.readyState)
        })
        window.addEventListener('load', (e) => {
            console.log('【load】')
        })

        document.addEventListener('DOMContentLoaded', (e) => {
            console.log('【DOMContentLoaded】')
        })        
    </script>
    <script defer src="./a.js"></script>
    <script async src="./b.js"></script>
    <script src="./c.js"></script>
</head>
<body>
    <div class="container"></div>
</body>
</html>

網(wǎng)絡

頁面中分別引入了一個css資源,三個JS資源以及一個內(nèi)聯(lián)腳本,我們可以看下各資源的加載情況

圖片圖片

首先肯定是先加載html文件,而html中的cssjs資源會以他們在文檔中的順序依次進行請求加載,由于內(nèi)聯(lián)腳本無需再發(fā)起請求,所以在網(wǎng)絡模塊中也不會有它的存在。

注意看紅線位置,這是html開始解析的時間點,從network模塊上看,內(nèi)部的css與js資源竟然在這之前就發(fā)起了請求,這也就驗證了為了加速,瀏覽器的預加載掃描器會同時運行,如果在 html 中存在  <link><script>、img 等標簽,預加載掃描器會把這些請求傳遞給瀏覽器進程中的網(wǎng)絡線程進行相關資源的下載。

從圖中我們可以看到,a.cssc.js文件右上角都出現(xiàn)了紅色標注,這是代表這兩個文件都會阻塞頁面的渲染

圖片圖片

為了更清晰的了解各模塊的加載解析與渲染之間的關系,我們可以查看下方的主線程模塊

主線程

圖片圖片

可以看到html的解析、css的解析、腳本的執(zhí)行、頁面渲染等都發(fā)生在主線程

parse html

在瀏覽器渲染引擎內(nèi)部,有一個叫HTML 解析器(HTMLParser)的模塊,它負責將HTML字節(jié)流轉換為DOM結構。HTML Standard規(guī)范定義了瀏覽器渲染HTML為DOM的方法。

??需要注意的是HTML解析器并不是等整個文檔加載完成之后再解析的,而是網(wǎng)絡進程加載了多少數(shù)據(jù),HTML解析器就解析多少數(shù)據(jù)。

圖片圖片

注意看,第一次解析html的范圍是0-24,解析過程遇到了css資源,等css資源下載完成后會開始解析css(這個過程不會阻塞html的解析)

parse stylesheet

圖片圖片

Evaluate script

再往后就遇到了內(nèi)聯(lián)腳本,這個時候會停下來解析執(zhí)行JS(這才是導致html解析暫停的根本原因)

圖片圖片

等腳本執(zhí)行完后會繼續(xù)解析html

圖片圖片

注意range,跟上一次parse html剛好接上了

接著往后會依次遇到a、b、c三個腳本,由于c沒有添加任何異步屬性,所以c會率先開始執(zhí)行(此時會阻塞html的解析)

圖片圖片

執(zhí)行完成后會繼續(xù)解析html

圖片圖片

等解析完成后會開始執(zhí)行標記了defera.js(a.js在這之前就已加載完成)

圖片圖片

最后標記了asyncb.js加載完成,會立即執(zhí)行

圖片圖片

責任編輯:武曉燕 來源: 前端南玖
相關推薦

2013-11-20 10:47:57

瀏覽器渲染html

2020-11-06 15:20:45

瀏覽器前端架構

2017-10-09 13:39:26

瀏覽器渲染服務器

2019-04-08 10:27:00

渲染瀏覽器DOM

2013-11-18 14:42:53

瀏覽器渲染

2017-11-21 14:56:59

2012-06-01 10:28:54

Web

2012-06-06 15:57:29

Web

2013-05-23 16:01:56

瀏覽器

2013-06-14 13:56:29

瀏覽器渲染原理

2017-04-26 14:15:35

瀏覽器緩存機制

2017-08-03 12:50:49

Web圖片資源瀏覽器

2013-11-20 13:47:43

瀏覽器渲染引擎

2017-03-08 08:31:48

瀏覽器渲染路徑

2022-08-30 09:01:11

瀏覽器渲染前端

2018-01-19 14:39:53

瀏覽器頁面優(yōu)化

2021-01-07 07:52:04

瀏覽器網(wǎng)頁資源加載

2021-12-17 00:02:28

Webpack資源加載

2015-02-28 09:39:24

Windows 10Spartan

2017-03-12 10:15:18

瀏覽器DOM樹CSSOM樹
點贊
收藏

51CTO技術棧公眾號