为什么说js操作DOM很慢
Posted yaobai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么说js操作DOM很慢相关的知识,希望对你有一定的参考价值。
DOM
文档对象模型(Document Object Model简称DOM),是W3C组织推荐的处理扩展标记语言的标准编程接口。在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标准模型就成为DOM。DOM的历史追溯至1990年代后期微软于Netscape的“浏览器大战”。双方为了在javascript和JScript一决生死,于是大规模的赋予浏览器强大的功能。微软在网页技术上计入了不少专属事物,既有VBScript,ActivityX,以及微软自家的Dhtml格式等,使不少网页使用非微软平台及浏览器无法正常显示。DOM即是当时酝酿出来的杰作。
优点和缺点
DOM的优势主要在于易用性强,使用DOM时,将把所有的XML文档信息都存在于内存中,并且遍历简单,支持XPath,增强了易用性。
DOM的缺点主要表现在效率低,内存占用量过高,对于大文件来说几乎不可能。另外效率低还表现在大量的消耗时间,因为使用DOM进行解析时,将文档的每个Element,Attribute,Processing-instruction和Comment都创建了一个对象,这样在DOM机制中运用了大量对象的创建和销毁无疑影响其效率。
为什么说js操作DOM会影响性能呢?
在浏览器中DOM得实现和ECMAScript是分离得。
在IE中EMCMAScript是实现在jscript.dll中,DOM实现在mshtml.dll中。在Chrome中使用Webkit中的WebCore处理DOM和渲染,ECMAScript是在V8引擎中实现的。其他浏览器也类似。
因此在使用js操作DOM的时候是通过js代码调用DOM的接口,这就相当于两个互相独立的模块发生交互,这样的性能损耗是非常高的。
然而影响DOM操作性能的主要原因是它会导致浏览器重绘和重排。
浏览器渲染的原理
我以前写过:站在浏览器角度谈前端优化
简单理解为浏览器解析html形成DOM树,解析css形成CSSOM树,然后他两合并成渲染树。然后根据Layout布局映射到屏幕上。当页面发生重绘或者重排的话,浏览器会重新计算,消耗很多性能,
重绘
页面某些部分需要重新绘制,由于节点的几何属性发生改变或者由于样式发生变化。例如改变元素的背景,屏幕上的部分内容发生改变需要更新,发生重绘。发生重绘元素的位置和尺寸都不会变,
重排
元素的位置或者尺寸发生改变。浏览器会重新计算渲染树。因为位置和尺寸更改势必会影响整体的布局,这样损耗的性能比较高。分为部分重排和全部重排,应该避免全部重排。重排必会重绘。
优化方法
(1)把DOM累计起来批量操作。offsetTop/Left/Width/Height
、scrollTop/Left/Width/Height
、clientTop/Left/Width/Height
、getComputedStyle()
或 currentStyle
。因为这些值都是动态计算的,必然会打乱重绘和重排。
(2)合并多次DOM操作为单次DOM操作
例1:
这样操作就会发生DOM重绘或重排3次;
element.style.borderColor = \'#f00\';
element.style.borderStyle = \'solid\';
element.style.borderWidth = \'1px\';
合并的话只操作一次;
element.style.cssText += \'border: 1px solid #f00;\';
例2:
以前我经常这样动态插入列表
for (var i = 0; i < data.lengt; i++) {
var html = `<li>${data[i].title}</li>`;
$("ul").append(html);
}
改为拼接字符串,最后插入DOM
var html = "";
for (var i = 0; i < data.lengt; i++) {
html += `<li>${data[i].title}</li>`;
}
$("ul").append(html);
(3)通过设置DOM元素的display样式为none来隐藏元素,这样引起的重排或重绘只是在显示和隐藏这两步
$("ul").css("display", "none");
for (var i = 0; i < data.lengt; i++) {
var html = `<li>${data[i].title}</li>`;
$("ul").append(html);
}
$("ul").css("display", "block");
(4)克隆DOM到内存中,经过一系列操作,最后影响性能得就是最后一步了。
var yb_li = $("ul li").clone();
yb_li.text(\'yaobai\');
yb_li.css(\'color\', "red");
$("ul").append(yb_li);
(5)设置具有动画效果得DOM元素的position属性为fixed或absolute。
把页面具有动画效果的元素设置为绝对定位,使得元素脱离页面布局流,这样只涉及动画元素自身重排了,这种做法可以提高动画效果的展示性能。
(6)缓存DOM对象,避免每次都从整个DOM树种查找
不推荐
$(\'#mod .active\').remove(\'active\');
$(\'#mod .not-active\').addClass(\'active\');
推荐
let $mod = $(\'#mod\');
$mod.find(\'.active\').remove(\'active\');
$mod.find(\'.not-active\').addClass(\'active\');
以上是关于为什么说js操作DOM很慢的主要内容,如果未能解决你的问题,请参考以下文章