DOM优化

1.节点修改

使用cloneNode在外部更新节点然后再通过replace与原始节点互换。

window.onload = function () {
        var orij = document.getElementById('content');
        //新的内容替换原有的内容
        var clone = orij.cloneNode(false);
        //在原有内容的基础上进行修改
        //var clone = orij.cloneNode(true);
        var list = ['foo','bar','baz'];
        var content;
        for(var i = 0; i < list.length; i++){
            content = document.createTextNode(list[i]);
            clone.appendChild(content);
        }
        orij.parentNode.replaceChild(clone,orij);
    }

2.节点的添加

多个节点插入操作,即使在外面设置节点的元素和风格再插入,由于多个节点还是会引发多次reflow。
优化的方法是创建DocumentFragment,在其中插入节点后再添加到页面。

 var btn = document.getElementById('btn');
        btn.onclick = function () {
            var list = document.getElementById('list');
            var fragment = document.createDocumentFragment();
            for(var i = 0; i < 5 ; i ++){
                var li = document.createElement('li');
                li.textContent = i;
                fragment.appendChild(li)
            }
            list.appendChild(fragment);
        }

3.CSS样式转换

如果需要动态更改CSS样式,尽量采用触发reflow次数较少的方式。
可以通过直接设置元素的className直接设置,只会触发一次reflow。

//css
.content{
            width:200px;;
            height:200px;
            background-color: aqua;
        }
        .container{
            background-color: pink;
            width:200px;
            height: 200px;
        }

//HTML
<div class="content" id="content"></div>

//js
document.getElementById('content').className = "container";

4.减少DOM元素数量

在控制台的console中输入下面的语句查看DOM元素数量:

document.getElementsByTagName( '*' ).length

正常页面的DOM元素数量一般不应该超过1000。
DOM元素过多会使DOM元素查询效率,样式表匹配效率降低,是页面性能最主要的瓶颈之一。

5.DOM操作

  • DOM操作性能问题主要有以下原因:

    • DOM元素过多导致元素定位缓慢。
    • 大量的DOM接口调用。
    • Javascript和DOM之间的交互需要通过函数API接口来完成,造成延时,尤其是在循环语句中。
    • DOM操作触发频繁的reflow(layout)和repaint。
    • layout发生在repaint之前,所以layout相对来说会造成更多性能损耗。
      • reflow(layout)就是计算页面元素的几何信息。
      • repaint就是绘制页面元素。
    • 对DOM进行操作会导致浏览器执行回流reflow。
  • 解决方法:

    • 纯JAVASCRIPT执行时间是很短的。
    • 最小化DOM访问次数,尽可能在js端执行。
    • 如果需要多次访问某个DOM节点,请使用局部变量存储对它的引用。
    • 谨慎处理HTML集合(HTML集合实时连系底层文档),把集合的长 度缓存到一个变量中,并在迭代中使用它,如果需要经常操作集合,建议把它拷贝到一个数组中。
    • 如果可能的话,使用速度更快的API,比如querySelectorAll和firstElementChild。
    • 要留意重绘和重排。
    • 批量修改样式时,离线操作DOM树。
    • 使用缓存,并减少访问布局的次数。
    • 动画中使用绝对定位,使用拖放代理。
    • 使用事件委托来减少事件处理器的数量。

事件委托示例

//HTML
<ul id="list">
    <li id="go">go something</li>
    <li id="do">do something</li>
    <li id="sayhi">say hi</li>
</ul>

//JS
var list = document.getElementById('list');
            list.addEventListener('click',function (event) {
                switch(event.target.id){
                    case 'go':
                        alert('aaa');
                        break;
                    case 'do':
                        document.title = 'I change document title';
                        break;
                    case 'sayhi':
                        location.href = '//www.greatytc.com/p/91cb28114c82';
                        break;
                }
            })

5.DOM交互

在JAVASCRIPT中,DOM操作和交互要消耗大量时间,因为它们往往需要重新渲染整个页面或者某一个部分。

  • 最小化现场更新
    当需要访问的DOM部分已经被渲染为页面中的一部分,那么DOM操作和交互的过程就是再进行一次现场更新。

    • 现场更新是需要针对现场(相关显示页面的部分结构)立即进行更新,每一个更改(不管是插入单个字符还是移除整个片段),都有一个性能损耗。
    • 现场更新进行的越多,代码完成执行所花的时间也越长。
  • 多使用innerHTML
    有两种在页面上创建DOM节点的方法:

    • 使用诸如createElement()和appendChild()之类的DOM方法。
    • 使用innerHTML。
      • 当使用innerHTML设置为某个值时,后台会创建一个HTML解释器,然后使用内部的DOM调用来创建DOM结构,而非基于Javascript的DOM调用。由于内部方法是编译好的而非解释执行,故执行的更快。

对于小的DOM更改,两者效率差不多,但对于大的DOM更改,innerHTML要比标准的DOM方法创建同样的DOM结构快得多。

6.回流reflow

  • 发生场景。
    • 改变窗体大小。
    • 更改字体。
    • 添加移除stylesheet块。
    • 内容改变哪怕是输入框输入文字。
    • CSS虚类被触发如 :hover。
    • 更改元素的className。
    • 当对DOM节点执行新增或者删除操作或内容更改时。
    • 动态设置一个style样式时(比如element.style.width="10px")。
    • 当获取一个必须经过计算的尺寸值时,比如访问offsetWidth、clientHeight或者其他需要经过计算的CSS值。
  • 解决问题的关键,就是限制通过DOM操作所引发回流的次数。
    • 在对当前DOM进行操作之前,尽可能多的做一些准备工作,保证N次创建,1次写入。
    • 在对DOM操作之前,把要操作的元素,先从当前DOM结构中删除:
      • 通过removeChild()或者replaceChild()实现真正意义上的删除。
      • 设置该元素的display样式为“none”。
    • 每次修改元素的style属性都会触发回流操作。
      • element.style.backgroundColor = "blue";
      • 使用更改className的方式替换style.xxx=xxx的方式。
      • 使用style.cssText = '';一次写入样式。
      • 避免设置过多的行内样式。
      • 添加的结构外元素尽量设置它们的位置为fixed或absolute。
      • 避免使用表格来布局。
      • 避免在CSS中使用JavaScript expressions(IE only)。
    • 将获取的DOM数据缓存起来。这种方法,对获取那些会触发回流操作的属性(比如offsetWidth等)尤为重要。
    • 当对HTMLCollection对象进行操作时,应该将访问的次数尽可能的降至最低,最简单的,你可以将length属性缓存在一个本地变量中,这样就能大幅度的提高循环的效率。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容

  • AJax 优化 缓存 Ajax 请求尽量使用GET, 仅取决于cookie数量 Cookie 优化 减少Cooki...
    KeKeMars阅读 9,360评论 5 89
  • DOM 一,DOM学习资源 MDN 、DOM specifications 二、学习方法 看别人封装的代码 方...
    从前慢pearl阅读 382评论 0 0
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,754评论 1 92
  • 转载说明 一、介绍 浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工作原理,我们将看到,从你在地址栏输入g...
    17碎那年阅读 2,450评论 0 22
  • “这不就是一团乱麻吗!”“一滩烂泥!”“复制粘贴而已,我也会。”………… 以上对于现代艺术的评价,相信大家都听过,...
    点融黑帮阅读 995评论 1 14