资讯专栏INFORMATION COLUMN

前端性能优化(DOM操作篇)

BDEEFE / 1140人阅读

摘要:在内存中操作元素由于操作会导致浏览器的回流,回流需要花费大量的时间进行样式计算和节点重绘与渲染,所以应当尽量减少回流次数。

正巧看到在送书,于是乎找了找自己博客上记录过的一些东西来及其无耻的蹭书了~~~

小广告:更多内容可以看我的博客

缓存DOM对象

JavaScript的DOM操作可以说是JavaScript最重要的功能,我们经常要根据用户的操作来动态的增加和删除元素,或是通过AJAX返回的数据动态生成元素。比如我们获得了一个很多元素的数组data[],需要将其每个值生成一个li元素插入到一个id为container的ul元素中,最简单(最慢)的方式是:

var liNode, i, m;
for (i = 0, m = data.length; i < m; i++) {
    liNode = document.createElement("li");
    liNode.innerText = data[i];
    document.getElementById("container").appendChild(liNode);
}

这里每一次循环都会去查找id为container的元素,效率自然非常低,所以我们需要将元素在循环前查询完毕,在循环中仅仅是引用就行了,修改代码为:

var ulNode = document.getElementById("container");
var liNode, i, m;
for (i = 0, m = data.length; i < m; i++) {
    liNode = document.createElement("li");
    liNode.innerText = data[i];
    ulNode.appendChild(liNode);
}

缓存DOM对象的方式也经常被用在元素的查找中,查找元素应该是DOM操作中最频繁的操作了,其效率优化也是大头。在一般情况下,我们会根据需要,将一些频繁被查找的元素缓存起来,在查找它或查找它的子孙元素时,以它为起点进行查找,就能提高查找效率了。

在内存中操作元素

由于DOM操作会导致浏览器的回流,回流需要花费大量的时间进行样式计算和节点重绘与渲染,所以应当尽量减少回流次数。一种可靠的方法就是加入元素时不要修改页面上已经存在的元素,而是在内存中的节点进行大量的操作,最后再一并将修改运用到页面上。DOM操作本身提供一个创建内存节点片段的功能:document.createDocumentFragment(),我们可以将其运用于上述代码中:

var ulNode = document.getElementById("container");
var liNode, i, m;
var fragment = document.createDocumentFragment();
for (i = 0, m = data.length; i < m; i++) {
    liNode = document.createElement("li");
    liNode.innerText = data[i];
    fragment.appendChild(liNode);
}
ulNode.appendChild(fragment);

这样就只会触发一次回流,效率会得到很大的提升。如果需要对一个元素进行复杂的操作(删减、添加子节点),那么我们应当先将元素从页面中移除,然后再对其进行操作,或者将其复制一个(cloneNode()),在内存中进行操作后再替换原来的节点

一次性DOM节点生成

在这里我们每次都需要生成节点(document.createElement("li")),然后将其加入到内存片段中,我们可以通过innerHTML属性来一次性生成节点,具体的思路就是使用字符串拼接的方式,先生成相应的HTML字符串,最后一次性写入到ul的innerHTML中。修改代码为:

var ulNode = document.getElementById("container");
var fragmentHtml = "", i, m;
for (i = 0, m = data.length; i < m; i++) {
    fragmentHtml += "
  • " + data[i] + "
  • "; } ulNode.innerHTML = fragmentHtml;

    这样效率也会有提升,不过手动拼写字符串是相当麻烦的一件事

    通过类修改样式

    有时候我们需要通过JavaScript给元素增加样式,比如如下代码:

    element.style.fontWeight = "bold";
    element.style.backgroundImage = "url(back.gif)";
    element.style.backgroundColor = "white";
    element.style.color = "white";
    //...
    

    这样效率很低,每次修改style属性后都会触发元素的重绘,如果修改了的属性涉及大小和位置,将会导致回流。所以我们应当尽量避免多次为一个元素设置style属性,应当通过给其添加新的CSS类,来修改其CSS

    .element {
        background-image: url(back.gif);
        background-color: #fff;
        color: #fff;
        font-weight: "bold";
        /*...*/
    }
    
    element.className += " element";
    
    通过事件代理批量操作事件

    还是之前那个ul和添加li,如果我们需要给每个li都绑定一个click事件,就可能写出类似如下代码:

    var ulNode = document.getElementById("container");
    var fragment = document.createDocumentFragment();
    var liNode, i, m;
    var liFnCb = function(evt){
        //do something
    };
    for (i = 0, m = data.length; i < m; i++) {
        liNode = document.createElement("li");
        liNode.innerText = data[i];
        liNode.addEventListener("click", liFnCb, false);
        fragment.appendChild(liNode);
    }
    ulNode.appendChild(fragment);
    

    这里每个li元素都需要执行一次addEventListener()方法,如果li元素数量一多,就会降低效率。所以我们可以通过事件代理的方式,将事件绑定在ul上,然后通过event.target来确定被点击的元素是否是li元素,同时我们也可以使用innerHTML属性一次性创建节点了,修改代码为:

    var ulNode = document.getElementById("container");
    var fragmentHtml = "", i, m;
    var liFnCb = function(evt){
        //do something
    };
    for (i = 0, m = data.length; i < m; i++) {
        fragmentHtml += "
  • " + data[i] + "
  • "; } ulNode.innerHTML = fragmentHtml; ulNode.addEventListener("click", function(evt){ if(evt.target.tagName.toLowerCase() === "li") { liFnCb.call(evt.target, evt); } }, false);

    这样事件绑定的代码就只要执行一次,可以监听所有li元素的事件了。当然如果需要移除事件回调函数,我们也不需要循环遍历所有的li元素,只需要移除ul元素上的事件处理就行了

    文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/78070.html

    相关文章

    • 前端优化-Javascript(4.DOM优化)

      摘要:优化策略跟上面的大同小异,就是用局部变量缓存集合以及集合的长度,我就不进行实际测试了。例如错误的做法使用修改来进行优化如果需要动态修改,那么就使用批量处理操作并且让元素脱离文档流,等操作结束后再放回文档流中。 上篇我介绍了Javascript标识符查找方面的优化,可以看出在这方面的优化给性能带来的提升并不明显,甚至可以说基本没有影响。但是,我今天要分享的是前端Javascript优化的...

      Prasanta 评论0 收藏0
    • 前端性能优化DOM操作

      摘要:在内存中操作元素由于操作会导致浏览器的回流,回流需要花费大量的时间进行样式计算和节点重绘与渲染,所以应当尽量减少回流次数。 正巧看到在送书,于是乎找了找自己博客上记录过的一些东西来及其无耻的蹭书了~~~ 小广告:更多内容可以看我的博客 缓存DOM对象 JavaScript的DOM操作可以说是JavaScript最重要的功能,我们经常要根据用户的操作来动态的增加和删除元素,或是通过...

      baukh789 评论0 收藏0
    • JS基础--JS的DOM操作 - 你真的了解吗?

      摘要:摘要想稍微系统的说说对于的操作把和常用操作的内容归纳成思维导图方便阅读同时加入性能上的一些问题前言在前端开发的过程中极为重要的一个功能就是对对象的操作无论增删改查在前端页面操作这一范围内都是比较消耗性能的如何高效率的便捷的操作这就是本文要讲 摘要 想稍微系统的说说对于DOM的操作,把Javascript和jQuery常用操作DOM的内容归纳成思维导图方便阅读,同时加入性能上的一些问题....

      DirtyMind 评论0 收藏0
    • 前端优化 - 收藏集 - 掘金

      摘要:虽然有着各种各样的不同,但是相同的是,他们前端优化不完全指南前端掘金篇幅可能有点长,我想先聊一聊阅读的方式,我希望你阅读的时候,能够把我当作你的竞争对手,你的梦想是超越我。 如何提升页面渲染效率 - 前端 - 掘金Web页面的性能 我们每天都会浏览很多的Web页面,使用很多基于Web的应用。这些站点看起来既不一样,用途也都各有不同,有在线视频,Social Media,新闻,邮件客户端...

      VincentFF 评论0 收藏0
    • 浅谈网站性能前端性能优化

      摘要:浅谈网站性能之前端性能优化性能优化的目的无非是减少用户流量消耗,提升用户首屏体验,提升用户访问速度,让用户专注内容本身。前端性能优化减少请求数量基本原理在浏览器与服务器进行通信时,主要是通过进行通信。 最近项目慢慢走上正轨,需求趋于平稳,这才想起需要对整站进行性能优化。经过一段时间的学习,结合现在项目的实际性能情况,发现确实有许多地方可以进行优化。于是就开始了我的前端性能优化之旅。以下...

      Winer 评论0 收藏0

    发表评论

    0条评论

    BDEEFE

    |高级讲师

    TA的文章

    阅读更多
    最新活动
    阅读需要支付1元查看
    <