Dom操作的性能优化

        在 开发过程中,或多或少都会遇到要操作dom的情况,而dom操作多多少少都会耗费一些性能,那今天我们就一起来看看在操作dom的时候有哪些性能优化方式吧:

1.选择性能更好的获取dom元素的方法

首先,我们一起来看看,如何使用js来获取dom元素:

  • document.getElementById() / getElementsByClassName() / getElementByTagName()
  • document.querySelector() / querySelectorAll()

以上方法,都可以帮助我们获取到dom元素,但getElementXX 和 querySelectorXX 选择哪个更能节约一些性能呢?我们一起来看看吧:

首先,我们需要知道它俩获取出来的DOM集合有什么区别:

让我们一起来看一下下面这两个例子分别打印出来的结果是什么 ?

在浏览器中执行一下,会发现使用getElementsByClassName获取的DOM元素最后打印的length为2 , 使用querySelectorAll 获取的DOM元素最后打印length为1。

这是因为 getElementXX 获取的是一个HTML集合,它是一种“假定实时态”,意味着底层文档对象更新,它也会跟着更新。

而 querySelectorXX 获取的是一个NodeList集合,它不会实时返回文档结构,只会保存当前获取时的DOM结构。

因为 getElementXX 的实时更新,它的性能会比querySelector差很多,如不稍不注意还容易导致死循环 :

所以获取DOM元素尽可能使用querySelectorXX,如果必须要用getElementXX也请浅拷贝 [...boxs] 一下,来避免它的“假定实时态”。

 2.减少不必要的dom操作

我们应该都知道在浏览器实现js的操作和DOM的操作是分别独立的,js的实现名为JScript,位于jscript.dll文件中;DOM的实现存在另外一个库中,名叫mshtml.dll。

由于两者完全独立,如果两者需要沟通可以想象在他们之间建立一座“高架桥”,每次经过都需要收取“过路费”,是不是听起来就很耗费性能?所以我们应该尽可能减少经过这座“高架桥”。

尝试将DOM缓存起来:

如下图所示:第一种做法我们将经过两次“高架桥”,如果想要获取更多的属性那需要经过更多次“高架桥”。而第二种我们将DOM缓存起来,无论获取多少属性值都只需要经过一次“高架桥”。

 尽可能将更新DOM操作统一起来:

如下图所示:通过下面的两个函数 innerHTMLLoop 和 innerHTMLLoop2 执行时间来看,将需要更新的内容先缓存起来,再一次性更新到页面上效率高很多。

还有一种场景,例如我们想一次性插入1000个<li/>节点到 ul.container 中,按照常规想法我们会这样做:

如果这样做我们就像container添加了1000次,相当于经过“高架桥”1000次,我们如何通过一次来更新1000次的操作呢?

实际上是有方案的:

我们可以通过生成一个虚拟的节点对象 document.createDocumentFragement 来让1000次更新先添加到这个虚拟节点,再统一更新到container上。

还有一种方案就是:

把 .contianer{display:none;} 再向cotianer.appendClind子元素,最后通过display:block展示出来。display: none的元素不会引起页面的重排 and 重绘,也会减轻性能。 

我们可以根据自己的使用场景去选择使用方法。只要记住减少频繁的跟DOM操作即可

3.减少页面重排 and 重绘次数

上面我们提到过更新、添加页面中的DOM元素,其实只要是页面中元素发生更改,都会引发页面的重排 or 重绘。

当然浏览器也不傻,重排很耗费性能,他不会在你一需要重绘的时候就立马帮你重排 and 重绘,它会缓存一个队列定期重排 and 重绘,但有一些属性会强制页面重排 and 重绘

  • offsetTop/Left/Width/Height
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height

所以我们应该尽量减少这类属性的使用,如果要使用也将它缓存起来不要频繁获取。 

今天的内容就到这里结束啦,希望对大家有帮助。

猜你喜欢

转载自blog.csdn.net/weixin_46422035/article/details/121697060