0
点赞
收藏
分享

微信扫一扫

高效前端:不容小觑的DOM性能优化实践


提起DOM,大多数人大概都会认为这是一个不怎么重要的概念,以至于在有些关于性能优化的书中都对此闭口不谈,但其实我觉得DOM有关的性能优化在前端开发工作中起着非常重要的作用——DOM是将Web页面与脚本或其它编程语言(JavaScript)连接的桥梁。

众所周知,DOM也是Web页面实现面向对象编程的中介。我们的网页都是由HTML元素构成的,而每一个HTML元素都是一个DOM节点,一个一个的DOM节点就构成了我们平时所说的DOM树,正如 万物皆对象 ,所以我们的每个DOM节点,甚至是整个DOM树都可以看成对象,我们可以使用JavaScript操作这些DOM节点,以实现丰富的交互功能。

DOM优化的背景:

在没有Vue、React的年代,要实现复杂的交互,需要获取对应元素,然后再进行各种操作,但这样操作DOM时非常耗费性能的。仅仅是一个节点的属性就非常多:

高效前端:不容小觑的DOM性能优化实践_性能优化


关于DOM的优化:

我在​​本专栏​​的其他文章中曾提过一些优化建议,比如:不要嵌套多个无用的div能用css实现的就不要写HTML或js 等。

在React框架中,如果遇到必须要一个父元素包裹的情况,我们可以用< Fragment >标签来实现,它不会在DOM树中创建对应的节点,也就意味着对性能和效率(比如:重绘)来说,是个不错的选择。

我们常常会用到如下形式的代码,比如在网页中的导航栏处,或者在选项卡中:为每个

  • 标签(菜单)添加点击事件。
    你是否会写出如下代码:

let container = document.getElementById('container');
let wrapper = document.createDocumentFragment
for(let i = 0; i < data.length; i++ ){
let li = document.createElement('li');
li.innerText = data[i];
li.addEventListener('click', function(){
// 触发click后要做的事情
},false)
wrapper.appendChild(li);
}
container.appendChild(wrapper);

这是很“可怕”的一端代码:假设这里有一万条数据,那么就需要执行一万次监听事件,这对性能影响是很大的!
我们可以用事件代理机制来解决这个问题:

let container = document.getElementById('container');
let wrapper = document.createDocumentFragment
for(let i = 0; i < data.length; i++ ){
let li = document.createElement('li');
li.innerText = data[i];
}
wrapper.appendChild(li);
container.appendChild(wrapper);
container.addEventListener('click', function(e){
target = e.target || e.srcElement; //同Vue,这里的e就指代了li事件,而e.target就指向了li标签(比如Vue中input的e.target.value就指向(代表)了框内的内容)
if(target.tagName.toLowerCase() == 'li'){
// 触发click后要做的事情
}
}, false)

这样的话我们就把事件挂在了父元素上面,如果有对应事件被触发,再去找对应的元素即可。

当然,我还有一点优化建议:一些简单的事件,完全可以用css完成,在js中只用通过css样式的增加(addClass)与删去(remove)来挂载 。这对于大型数据下的HTML是非常优化的。

这里我们用了DocumentFragments来创建一个节点元素,将其作为代理加到父元素上的方法。其实这也是一个优化措施。DocumentFragments是DOM节点,但不是主DOM树的一部分,通常的用例是创建文档片段,将元素附加到文档片段上,然后将文档片段加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。
因为文档片段存于内存中,并不在DOM树中,所以讲子元素插入到文档片段时不会引起页面回流。可以带来更好的性能体验。


举报

相关推荐

0 条评论