日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

html中dom多会有影响吗,DOM操作造成的页面卡顿问题及解决

發布時間:2025/3/15 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 html中dom多会有影响吗,DOM操作造成的页面卡顿问题及解决 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

相關目錄

以下為我總結的其他性能優化點,歡迎參考,指點及吐槽

前言

界面上UI的更改都是通過DOM操作實現的,并不是通過傳統的刷新頁面實現 的。盡管DOM提供了豐富接口供外部調用,但DOM操作的代價很高,頁面前端代碼的性能瓶頸也大多集中在DOM操作上,所以前端性能優化的一個主要的關注 點就是DOM操作的優化。

DOM操作優化的總原則是盡量減少DOM操作。

先來看看DOM操作為什么會影響性能?

在瀏覽器中,DOM的實現和ECMAScript的實現是分離的。比如 在IE中,ECMAScrit的實現在jscript.dll中,而DOM的實現在mshtml.dll中;在Chrome中使用WebKit中的 WebCore處理DOM和渲染,但ECMAScript是在V8引擎中實現的,其他瀏覽器的情況類似。所以通過JavaScript代碼調用DOM接 口,相當于兩個獨立模塊的交互。相比較在同一模塊中的調用,這種跨模塊的調用其性能損耗是很高的。但DOM操作對性能影響最大其實還是因為它導致了瀏覽器 的重繪(repaint)和回流(reflow)。

這里我們先了解下瀏覽器的渲染原理:

從下載文檔到渲染頁面的過程中,瀏覽器會通過解析HTML文檔來構建DOM樹,解析CSS產生CSS規則樹。JavaScript代碼在解析過程中, 可能會修改生成的DOM樹和CSS規則樹(這也是為什么常常把js放在頁面底部最后才渲染的原因)。之后根據DOM樹和CSS規則樹構建渲染樹,在這個過程中CSS會根據選擇器匹配HTML元素。渲染樹包括了每 個元素的大小、邊距等樣式屬性,渲染樹中不包含隱藏元素及head元素等不可見元素。

最后瀏覽器根據元素的坐標和大小來計算每個元素的位置,并繪制這些元 素到頁面上。重繪指的是頁面的某些部分要重新繪制,比如顏色或背景色的修改,元素的位置和尺寸并沒用改變;回流則是元素的位置或尺寸發生了改變,瀏覽器需 要重新計算渲染樹,導致渲染樹的一部分或全部發生變化。渲染樹重新建立后,瀏覽器會重新繪制頁面上受影響的元素。回流的代價比重繪的代價高很多,重繪會影 響部分的元素,而回流則有可能影響全部的元素。如下的這些DOM操作會導致重繪或回流:

增加、刪除和修改可見DOM元素

頁面初始化的渲染

移動DOM元素

修改CSS樣式,改變DOM元素的尺寸

DOM元素內容改變,使得尺寸被撐大

瀏覽器窗口尺寸改變

瀏覽器窗口滾動

如何避免或者處理DOM操作造成的頁面卡頓問題

1.合并多次的DOM操作為單次的DOM操作

最常見頻繁進行DOM操作的是頻繁修改DOM元素的樣式,代碼類似如下:

element.style.borderColor = '#f00';

element.style.borderStyle = 'solid';

element.style.borderWidth = '1px';

復制代碼

這種編碼方式會因為頻繁更改DOM元素的樣式,觸發頁面多次的回流或重繪,上面介紹過,現代瀏覽器針對這種情況有性能的優化,它會合并DOM操作,但并不是所有的瀏覽器都存在這樣的優化。推薦的方式是把DOM操作盡量合并,如上的代碼可以優化為:

// 優化方案1

element.style.cssText += 'border: 1px solid #f00;';

// 優化方案2

element.className += 'empty';

復制代碼

示例的代碼有兩種優化的方案,都做到了把多次的樣式設置合并為一次設置。方案2比方案1稍微有一些性能上的損耗,因為它需要查詢CSS類。但方案2的維護性最好,這在上一章曾經討論過。很多時候,如果性能問題并不突出,選擇編碼方案時需要優先考慮的是代碼的維護性。

類似的操作還有通過innerHTML接口修改DOM元素的內容。不要直接通過此接口來拼接HTML代碼,而是以字符串方式拼接好代碼后,一次性賦值給DOM元素的innerHTML接口。

2.把DOM元素離線或隱藏后修改

把DOM元素從頁面流中脫離或隱藏,這樣處理后,只會在DOM元素脫離和添加時,或者是隱藏和顯示時才會造成頁面的重繪或回流,對脫離了頁面布局流的DOM元素操作就不會導致頁面的性能問題。這種方式適合那些需要大批量修改DOM元素的情況。具體的方式主要有三種:

(1)使用文檔片段

文檔片段是一個輕量級的document對象,并不會和特定的頁面關聯。通過在文檔片段上進行DOM操作,可以降低DOM操作對頁面性能的影響,這 種方式是創建一個文檔片段,并在此片段上進行必要的DOM操作,操作完成后將它附加在頁面中。對頁面性能的影響只存在于最后把文檔片段附加到頁面的這一步 操作上。代碼類似如下:

var fragment = document.createDocumentFragment();

// 一些基于fragment的大量DOM操作

...

document.getElementById('myElement').appendChild(fragment);

復制代碼(2)通過設置DOM元素的display樣式為none來隱藏元素

這種方式是通過隱藏頁面的DOM元素,達到在頁面中移除元素的效果,經過大量的DOM操作后恢復元素原來的display樣式。對于這類會引起頁面重繪或回流的操作,就只有隱藏和顯示DOM元素這兩個步驟了。代碼類似如下:

var myElement = document.getElementById('myElement');

myElement.style.display = 'none';

// 一些基于myElement的大量DOM操作

...

myElement.style.display = 'block';

復制代碼(3)克隆DOM元素到內存中

這種方式是把頁面上的DOM元素克隆一份到內存中,然后再在內存中操作克隆的元素,操作完成后使用此克隆元素替換頁面中原來的DOM元素。這樣一來,影響性能的操作就只是最后替換元素的這一步操作了,在內存中操作克隆元素不會引起頁面上的性能損耗。代碼類似如下:

var old = document.getElementById('myElement');

var clone = old.cloneNode(true);

// 一些基于clone的大量DOM操作

...

old.parentNode.replaceChild(clone, old);

復制代碼

在現代的瀏覽器中,因為有了DOM操作的優化,所以應用如上的方式后可能并不能明顯感受到性能的改善。但是在仍然占有市場的一些舊瀏覽器中,應用以上這三種編碼方式則可以大幅提高頁面渲染性能。

3. 設置具有動畫效果的DOM元素的position屬性為fixed或absolute

把頁面中具有動畫效果的元素設置為絕對定位,使得元素脫離頁面布局流,從而避免了頁面頻繁的回流,只涉及動畫元素自身的回流了。這種做法可以提高動 畫效果的展示性能。如果把動畫元素設置為絕對定位并不符合設計的要求,則可以在動畫開始時將其設置為絕對定位,等動畫結束后恢復原始的定位設置。在很多的 網站中,頁面的頂部會有大幅的廣告展示,一般會動畫展開和折疊顯示。如果不做性能的優化,這個效果的性能損耗是很明顯的。使用這里提到的優化方案,則可以 提高性能。

4. 謹慎取得DOM元素的布局信息

前面討論過,獲取DOM的布局信息會有性能的損耗,所以如果存在重復調用,最佳的做法是盡量把這些值緩存在局部變量中。考慮如下的一個示例:

for (var i=0; i < len; i++) {

myElements[i].style.top = targetElement.offsetTop + i*5 + 'px';

}

復制代碼

如上的代碼中,會在一個循環中反復取得一個元素的offsetTop值,事實上,在此代碼中該元素的offsetTop值并不會變更,所以會存在不必要的性能損耗。優化的方案是在循環外部取得元素的offsetTop值,相比較之前的方案,此方案只是調用了一遍元素的offsetTop值。更改后的代碼如下:

var targetTop = targetElement.offsetTop;

for (var i=0; i < len; i++) {

myElements[i].style.top = targetTop+ i*5 + 'px';

}

復制代碼

另外,因為取得DOM元素的布局信息會強制瀏覽器刷新渲染樹,并且可能會導致頁面的重繪或回流,所以在有大批量DOM操作時,應避免獲取DOM元素 的布局信息,使得瀏覽器針對大批量DOM操作的優化不被破壞。如果需要這些布局信息,最好是在DOM操作之前就取得。考慮如下一個示例:

var newWidth = div1.offsetWidth + 10;

div1.style.width = newWidth + 'px';

var newHeight = myElement.offsetHeight + 10; // 強制頁面回流

myElement.style.height = newHeight + 'px'; // 又會回流一次

復制代碼

根據上面的介紹,代碼在遇到取得DOM元素的信息時會觸發頁面重新計算渲染樹,所以如上的代碼會導致頁面回流兩次,如果把取得DOM元素的布局信息提前,因為瀏覽器會優化連續的DOM操作,所以實際上只會有一次的頁面回流出現,優化后的代碼如下:

var newWidth = div1.offsetWidth + 10;

var newHeight = myElement.offsetHeight + 10;

div1.style.width = newWidth + 'px';

myElement.style.height = newHeight + 'px';

復制代碼

5. 使用事件托管方式綁定事件

在DOM元素上綁定事件會影響頁面的性能,一方面,綁定事件本身會占用處理時間,另一方面,瀏覽器保存事件綁定,所以綁定事件也會占用內存。頁面中 元素綁定的事件越多,占用的處理時間和內存就越大,性能也就相對越差,所以在頁面中綁定的事件越少越好。一個優雅的手段是使用事件托管方式,即利用事件冒 泡機制,只在父元素上綁定事件處理,用于處理所有子元素的事件,在事件處理函數中根據傳入的參數判斷事件源元素,針對不同的源元素做不同的處理。這樣就不 需要給每個子元素都綁定事件了,管理的事件綁定數量變少了,自然性能也就提高了。這種方式也有很大的靈活性,可以很方便地添加或刪除子元素,不需要考慮因 元素移除或改動而需要修改事件綁定。示例代碼如下:

// 獲取父節點,并添加一個click事件

document.getElementById('list').addEventListener("click",function(e) { // 檢查事件源元素 if(e.target && e.target.nodeName.toUpperCase == "LI") { // 針對子元素的處理 ...

}

});

復制代碼

上述代碼中,只在父元素上綁定了click事件,當點擊子節點時,click事件會冒泡,父節點捕獲事件后通過e.target檢查事件源元素并做相應地處理。

在JavaScript中,事件綁定方式存在瀏覽器兼容問題,所以在很多框架中也提供了相似的接口方法用于事件托管。比如在jQuery中可以使用如下方式實現事件的托管(示例代碼來自jQuery官方網站):

$( "table" ).on( "click", "td", function() { $( this ).toggleClass( "chosen" );

});

復制代碼

總結

以上是生活随笔為你收集整理的html中dom多会有影响吗,DOM操作造成的页面卡顿问题及解决的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。