DOM 大小過(guò)大對(duì)交互性的影響比您想象的要大贴捡。本指南介紹了原因以及您可以采取的行動(dòng)番枚。
這種解決辦法無(wú)法解決:當(dāng)您構(gòu)建某個(gè)網(wǎng)頁(yè)時(shí)法严,該網(wǎng)頁(yè)將擁有一個(gè)文檔對(duì)象模型 (DOM)。DOM 代表網(wǎng)頁(yè) HTML 的結(jié)構(gòu)葫笼,可以通過(guò) DOM 訪問(wèn)網(wǎng)頁(yè)的結(jié)構(gòu)和內(nèi)容深啤。
不過(guò),問(wèn)題在于 DOM 的大小會(huì)影響瀏覽器快速高效地渲染網(wǎng)頁(yè)的能力路星。一般來(lái)說(shuō)溯街,DOM 越大,最初渲染該網(wǎng)頁(yè)以及在網(wǎng)頁(yè)生命周期中稍后更新其渲染的開(kāi)銷(xiāo)就越大洋丐。
在具有非常大的 DOM 的頁(yè)面中呈昔,如果修改或更新 DOM 的互動(dòng)觸發(fā)開(kāi)銷(xiāo)大的布局工作,從而影響頁(yè)面快速響應(yīng)的能力友绝,就會(huì)出現(xiàn)問(wèn)題堤尾。高開(kāi)銷(xiāo)的布局工作可能會(huì)影響頁(yè)面的 Interaction to Next Paint (INP);如果您想讓頁(yè)面快速響應(yīng)用戶(hù)互動(dòng)迁客,請(qǐng)務(wù)必確保 DOM 大小僅根據(jù)需要調(diào)整郭宝。
頁(yè)面的 DOM 何時(shí)過(guò)大?
關(guān)鍵字:請(qǐng)務(wù)必了解 DOM 元素和 DOM 節(jié)點(diǎn)之間的區(qū)別哲泊。DOM 元素是指 DOM 樹(shù)中的特定 HTML 元素剩蟀。DOM 節(jié)點(diǎn)與 DOM 元素術(shù)語(yǔ)的含義重疊,但其定義已擴(kuò)展為包括注釋切威、空白和文本育特。雖然 Lighthouse DOM 大小審核涉及的是 DOM 節(jié)點(diǎn),但本指南將盡可能參考節(jié)點(diǎn)上的 DOM 元素先朦。
根據(jù) Lighthouse 的介紹缰冤,當(dāng)頁(yè)面超過(guò) 1,400 個(gè)節(jié)點(diǎn)時(shí),其 DOM 大小會(huì)過(guò)大喳魏。當(dāng)頁(yè)面的 DOM 超過(guò) 800 個(gè)節(jié)點(diǎn)時(shí)棉浸,Lighthouse 將開(kāi)始發(fā)出警告。以下面的 HTML 為例:
<ul>
<li>List item one.</li>
<li>List item two.</li>
<li>List item three.</li>
</ul>
以上代碼中有四個(gè) DOM 元素:<ul>
元素及其三個(gè) <li>
子元素刺彩。您的網(wǎng)頁(yè)肯定會(huì)有比這個(gè)數(shù)量多得多的節(jié)點(diǎn)迷郑,因此請(qǐng)務(wù)必了解如何控制 DOM 大小枝恋,以及在將網(wǎng)頁(yè)的 DOM 縮小到最小后,如何采用其他策略來(lái)優(yōu)化渲染工作嗡害。
較大的 DOM 對(duì)網(wǎng)頁(yè)性能有何影響焚碌?
大型 DOM 會(huì)以以下幾種方式影響頁(yè)面性能:
- 在網(wǎng)頁(yè)的初始呈現(xiàn)期間。將 CSS 應(yīng)用于網(wǎng)頁(yè)時(shí)霸妹,系統(tǒng)會(huì)創(chuàng)建一個(gè)與 DOM 類(lèi)似的結(jié)構(gòu)十电,稱(chēng)為 CSS 對(duì)象模型 (CSSOM)。隨著 CSS 選擇器的針對(duì)性越來(lái)越強(qiáng)叹螟,CSSOM 變得更加復(fù)雜鹃骂,需要更多的時(shí)間來(lái)運(yùn)行必要的布局、樣式設(shè)置罢绽、合成和繪制工作畏线,從而將網(wǎng)頁(yè)繪制到屏幕上。這項(xiàng)額外的工作會(huì)增加網(wǎng)頁(yè)加載期間早期發(fā)生的互動(dòng)延遲時(shí)間有缆。
- 當(dāng)交互通過(guò)插入或刪除元素象踊,或者通過(guò)修改 DOM 內(nèi)容和樣式來(lái)修改 DOM 時(shí),渲染該更新所需的工作可能成本非常高昂的布局棚壁、樣式杯矩、合成和繪制工作。與網(wǎng)頁(yè)的初始渲染一樣袖外,當(dāng) HTML 元素因互動(dòng)而被插入 DOM 時(shí)史隆,CSS 選擇器的特定性越高,渲染工作量就越大曼验。
- 當(dāng) JavaScript 查詢(xún) DOM 時(shí)泌射,對(duì) DOM 元素的引用存儲(chǔ)在內(nèi)存中。例如鬓照,如果您調(diào)用
document.querySelectorAll
來(lái)選擇頁(yè)面上的所有<div>
元素熔酷,并且結(jié)果返回大量 DOM 元素,那么內(nèi)存開(kāi)銷(xiāo)可能會(huì)相當(dāng)可觀豺裆。
- 當(dāng) JavaScript 查詢(xún) DOM 時(shí)泌射,對(duì) DOM 元素的引用存儲(chǔ)在內(nèi)存中。例如鬓照,如果您調(diào)用
Chrome DevTools 性能分析器中顯示的長(zhǎng)時(shí)間任務(wù)拒秘。顯示的耗時(shí)較長(zhǎng)的任務(wù)是通過(guò) JavaScript 將 DOM 元素插入大型 DOM 引起的。
所有這些因素都可能會(huì)影響互動(dòng)性臭猜,但上方列表中的第二項(xiàng)尤為重要躺酒。如果互動(dòng)導(dǎo)致 DOM 發(fā)生更改,則可能會(huì)觸發(fā)大量工作蔑歌,這可能會(huì)導(dǎo)致網(wǎng)頁(yè)上的 INP 較差羹应。
如何衡量 DOM 大小次屠?
您可以通過(guò)多種方式測(cè)量 DOM 大小园匹。第一種方法使用 Lighthouse雳刺。運(yùn)行審核時(shí),當(dāng)前網(wǎng)頁(yè) DOM 的統(tǒng)計(jì)信息將顯示在“避免 DOM 規(guī)模過(guò)大”審核的“診斷”標(biāo)題下偎肃。在此部分中煞烫,您可以看到 DOM 元素的總數(shù)、包含最多子元素的 DOM 元素以及最深的 DOM 元素累颂。
一種比較簡(jiǎn)單的方法是使用任何主流瀏覽器的開(kāi)發(fā)者工具中的 JavaScript 控制臺(tái)。如需獲取 DOM 中的 HTML 元素總數(shù)凛俱,您可以在網(wǎng)頁(yè)加載后在控制臺(tái)中使用以下代碼:
document.querySelectorAll('*').length;
注意:請(qǐng)注意紊馏,上面的代碼段僅包含 DOM 中的 HTML 元素數(shù)量。它不包含 DOM 中的所有節(jié)點(diǎn)蒲犬。
如果您想實(shí)時(shí)查看 DOM 大小更新朱监,還可以使用性能監(jiān)控工具。利用此工具原叮,您可以將布局和樣式設(shè)置操作(以及其他性能方面)與當(dāng)前 DOM 大小相關(guān)聯(lián)赫编。
Chrome 開(kāi)發(fā)者工具中的性能監(jiān)視器。在此視圖中奋隶,頁(yè)面的 DOM 節(jié)點(diǎn)當(dāng)前數(shù)量會(huì)以圖表的形式顯示擂送,同時(shí)還會(huì)顯示每秒執(zhí)行的布局操作和樣式重新計(jì)算次數(shù)。
如果 DOM 的大小接近 Lighthouse DOM 大小的警告閾值唯欣,或者完全失敗嘹吨,則下一步是確定如何減小 DOM 的大小,以提高網(wǎng)頁(yè)響應(yīng)用戶(hù)互動(dòng)的能力境氢,從而提升網(wǎng)站的 INP蟀拷。
如何衡量互動(dòng)影響的 DOM 元素?cái)?shù)量?
如果您在實(shí)驗(yàn)室中分析某個(gè)互動(dòng)速度緩慢的問(wèn)題萍聊,并懷疑該問(wèn)題可能與網(wǎng)頁(yè) DOM 的大小有關(guān)问芬,則可以選擇性能分析器中標(biāo)記為“重新計(jì)算樣式”的任何活動(dòng),然后觀察底部面板中的上下文數(shù)據(jù)寿桨,以確定受影響的 DOM 元素?cái)?shù)量此衅。
觀察樣式重新計(jì)算工作導(dǎo)致 DOM 中受影響的元素?cái)?shù)量。請(qǐng)注意牛隅,互動(dòng)軌道中互動(dòng)的陰影部分表示互動(dòng)時(shí)長(zhǎng)超過(guò) 200 毫秒的部分炕柔,這是 INP 的指定“良好”閾值。
在上面的屏幕截圖中媒佣,您可以看到作品的樣式重新計(jì)算(選中后)顯示了受影響元素的數(shù)量匕累。以上屏幕截圖顯示了 DOM 大小對(duì)包含很多 DOM 元素的頁(yè)面上的渲染工作的極端情況,此診斷信息在任何情況下都很有用默伍,可以確定 DOM 大小是否是影響下一幀繪制以響應(yīng)交互所需時(shí)間的限制因素欢嘿。
如何減小 DOM 大兴ニ觥?
除了檢查網(wǎng)站的 HTML 是否存在不必要的標(biāo)記外炼蹦,減小 DOM 大小的主要方法是減少 DOM 深度羡宙。如果您在瀏覽器開(kāi)發(fā)者工具的 Elements(元素)標(biāo)簽頁(yè)中看到如下所示的標(biāo)記,則表明您的 DOM 可能不必要地過(guò)深:
<div>
<div>
<div>
<div>
<!-- Contents -->
</div>
</div>
</div>
</div>
當(dāng)您看到這樣的模式時(shí)掐隐,可以通過(guò)展平 DOM 結(jié)構(gòu)來(lái)簡(jiǎn)化這些模式狗热。這樣做可以減少 DOM 元素的數(shù)量,并有可能幫助您簡(jiǎn)化網(wǎng)頁(yè)樣式虑省。
DOM 深度也可能是您使用的框架的特征匿刮。特別是,基于組件的框架(例如那些依賴(lài)于 JSX 的框架)要求您將多個(gè)組件嵌套在一個(gè)父級(jí)容器中探颈。
不過(guò)熟丸,許多框架都允許您使用 fragment 來(lái)避免嵌套組件。將 fragment 作為功能提供且基于組件的框架包括(但不限于)以下內(nèi)容:
通過(guò)在所選框架中使用 fragment伪节,您可以降低 DOM 深度光羞。如果您擔(dān)心扁平化 DOM 結(jié)構(gòu)對(duì)樣式的影響,不妨使用更現(xiàn)代(且更快)的布局模式怀大,例如 flexbox 或 grid纱兑。
其他值得一試的策略
即使您費(fèi)力地展平了 DOM 樹(shù)并移除了不必要的 HTML 元素,以盡可能減小 DOM 的體積叉寂,該 DOM 依然會(huì)非常龐大萍启,并且隨著其不斷變化來(lái)響應(yīng)用戶(hù)互動(dòng),這些渲染工作也會(huì)開(kāi)始屏鳍。如果您屬于這種情況勘纯,可以考慮采取一些其他策略來(lái)限制呈現(xiàn)工作。
考慮附加方法
在某些情況下钓瞭,網(wǎng)頁(yè)在首次呈現(xiàn)時(shí)驳遵,用戶(hù)最初無(wú)法看到其中的大部分內(nèi)容。這可能是一個(gè)通過(guò)在啟動(dòng)時(shí)省略 DOM 的這些部分來(lái)延遲加載 HTML 的機(jī)會(huì)山涡,但在用戶(hù)與需要網(wǎng)頁(yè)最初隱藏部分的網(wǎng)頁(yè)部分互動(dòng)時(shí)添加這些部分堤结。
這種方法在初始加載期間乃至加載后都很有用。對(duì)于初始網(wǎng)頁(yè)加載鸭丛,您預(yù)先承擔(dān)的渲染工作量較少竞穷,這意味著初始 HTML 有效負(fù)載將會(huì)更輕量,并且渲染速度更快鳞溉。這樣一來(lái)瘾带,在關(guān)鍵時(shí)刻,系統(tǒng)就會(huì)為互動(dòng)提供更多運(yùn)行機(jī)會(huì)熟菲,而主線程的注意力競(jìng)爭(zhēng)也會(huì)減少看政。
如果網(wǎng)頁(yè)的許多部分在加載時(shí)最初處于隱藏狀態(tài)朴恳,這還可以加快觸發(fā)重新渲染工作的其他互動(dòng)。不過(guò)允蚣,隨著其他互動(dòng)為 DOM 添加更多內(nèi)容于颖,渲染工作量將隨著 DOM 在整個(gè)頁(yè)面生命周期內(nèi)不斷擴(kuò)大而增多。
隨著時(shí)間的推移嚷兔,向 DOM 添加內(nèi)容并非易事森渐,這也是在各方面需要權(quán)衡的因素。如果您采用這種方式谴垫,則可能會(huì)發(fā)出網(wǎng)絡(luò)請(qǐng)求章母,以獲取數(shù)據(jù)來(lái)填充您打算添加到網(wǎng)頁(yè)的 HTML,以響應(yīng)用戶(hù)互動(dòng)翩剪。雖然正在處理的網(wǎng)絡(luò)請(qǐng)求不會(huì)計(jì)入 INP,但可能會(huì)增加感知延遲時(shí)間彩郊。如果可能前弯,請(qǐng)顯示正在加載的旋轉(zhuǎn)圖標(biāo)或其他指示器,以便用戶(hù)了解正在發(fā)生什么秫逝。
限制 CSS 選擇器的復(fù)雜性
當(dāng)瀏覽器解析 CSS 中的選擇器時(shí)恕出,它必須遍歷 DOM 樹(shù),以了解這些選擇器是否以及如何應(yīng)用于當(dāng)前布局违帆。這些選擇器越復(fù)雜浙巫,瀏覽器需要進(jìn)行的工作就越多,這樣瀏覽器才能執(zhí)行網(wǎng)頁(yè)的初始渲染刷后,而且在網(wǎng)頁(yè)由于互動(dòng)而發(fā)生變化時(shí)的畴,樣式重新計(jì)算和布局工作也會(huì)增加。
閱讀以下內(nèi)容了解詳情:縮小樣式計(jì)算的范圍并降低其復(fù)雜性尝胆。
使用 content-visibility
屬性
CSS 提供了 content-visibility
屬性丧裁,這實(shí)際上是一種延遲渲染屏幕外 DOM 元素的方法。當(dāng)元素接近視口時(shí)含衔,系統(tǒng)會(huì)按需渲染這些元素煎娇。content-visibility
的好處不僅在于可以減少初始網(wǎng)頁(yè)呈現(xiàn)的大量呈現(xiàn)工作,還可以在用戶(hù)互動(dòng)導(dǎo)致網(wǎng)頁(yè) DOM 發(fā)生更改時(shí)跳過(guò)屏幕外元素的呈現(xiàn)工作贪染。
閱讀以下內(nèi)容了解詳情:content-visibility
:提升渲染性能的新 CSS 屬性缓呛。
總結(jié)
將 DOM 大小縮減到僅包含嚴(yán)格必要的內(nèi)容,是優(yōu)化網(wǎng)站 INP 的好方法杭隙。這樣做可以減少 DOM 更新后瀏覽器執(zhí)行布局和渲染工作所需的時(shí)間哟绊。即使您無(wú)法顯著縮減 DOM 大小,也可以使用一些技術(shù)將渲染工作隔離到 DOM 子樹(shù)寺渗,例如 CSS 封裝和 content-visibility
CSS 屬性匿情。
無(wú)論您采用何種方法兰迫,只要?jiǎng)?chuàng)建一個(gè)盡可能減少渲染工作量的環(huán)境,并減少網(wǎng)頁(yè)在響應(yīng)互動(dòng)時(shí)執(zhí)行的渲染工作量炬称,最終都會(huì)讓用戶(hù)在與您的網(wǎng)站互動(dòng)時(shí)感覺(jué)到更快的響應(yīng)速度汁果。這意味著,您網(wǎng)站的 INP 會(huì)降低玲躯,從而帶來(lái)更好的用戶(hù)體驗(yàn)据德。