9

我知道进行多次 dom 操作是不好的,因为它会强制多次重绘。

IE:

$('body').append('<div />')
         .append('<div />')
         .append('<div />')
         .append('<div />');

相反,更好的做法显然是:

$('body').append('<div><div></div><div></div><div></div><div></div></div>');

但我对虚拟操作很好奇

IE:

$('<div />').append('<div />')
            .append('<div />')
            .append('<div />')
            .append('<div />')
            .appendTo('body');

它仍然很糟糕吗,显然多次调用函数会产生一些开销,但是会不会对性能造成严重影响?


我问的原因是这样的:

var divs = [
    {text: 'First',  id: 'div_1', style: 'background-color: #f00;'},
    {text: 'Second', id: 'div_2', style: 'background-color: #0f0;'},
    {text: 'Third',  id: 'div_3', style: 'background-color: #00f;'},
    {text: 'Fourth', id: 'div_4', style: 'background-color: #f00;'},
    {text: 'Fifth',  id: 'div_5', style: 'background-color: #0f0;'},
    {text: 'Sixth',  id: 'div_6', style: 'background-color: #00f;'}
];

var element = $('<div />');

$.each(divs, function(i,o){
    element.append($('<div />', o));
});

$('body').append(element);

想象一下 divs 数组来自描述表单的数据库表(好吧,我在示例中使用 div,但它可以很容易地用输入替换)或类似的东西。

或使用我们拥有的“推荐”版本:

var divs = [
    {text: 'First',  id: 'div_1', style: 'background-color: #f00;'},
    {text: 'Second', id: 'div_2', style: 'background-color: #0f0;'},
    {text: 'Third',  id: 'div_3', style: 'background-color: #00f;'},
    {text: 'Fourth', id: 'div_4', style: 'background-color: #f00;'},
    {text: 'Fifth',  id: 'div_5', style: 'background-color: #0f0;'},
    {text: 'Sixth',  id: 'div_6', style: 'background-color: #00f;'}
];

var element = '<div>';

$.each(divs, function(i,o){
    element += '<div ';

    $.each(o, function(k,v){
        if(k != 'text'){
            element += k+'="'+v+'" ';
        }            
    });

    element += '>'+o.text+'</div>';

});

element += '</div>';

$('body').append(element);
4

4 回答 4

10

首先,虽然很高兴阅读这样的潜在性能影响,但您应该始终从测量开始,看看您是否有问题。

如果您无法察觉问题,请编写最易读的代码。

如果你能察觉到问题,测量、改变和测量。

说了这么多,您发布的最后一个示例涉及尚未写入 DOM 的元素,因此在将appendTo元素添加到 DOM 之前不会重新绘制。

如果您能捕捉到第二个和第三个示例之间的速度差异,我会感到非常惊讶 - 如果您能看到它们之间的任何主要差异,我会感到非常惊讶。

于 2012-11-02T23:39:22.740 回答
1

如果您在附加节点时真的担心性能,则需要使用文档片段。这些将允许您在不重新绘制的情况下将元素附加到 dom。John Resign 有一篇关于这个主题的优秀文章。他注意到性能提高了 200-300%。我在我的一个应用程序中实现了文档片段,并且可以确认他的说法。

于 2012-11-02T23:41:47.403 回答
1

运行时良好的旧标记生成发生了什么?说真的,怎么了?

我同意@Sohnee 关于可读性重要性的观点,但 DOM 操作是浏览器可以执行的一些最昂贵的操作。维护一串标记的选项可以变得完全可读,并提供可以忽略不计的用户体验改进。

这个 jsperf中,我们在运行时创建了一个 10x100 的表 - 一个非常合理的(并且不是迄今为止最复杂的场景)数据分页。在运行最新版本 Chrome 的四核机器上,直接 DOM 操作脚本需要 60 毫秒才能完成,而标记缓存则需要 3 毫秒。

这在我的设置上是一个难以区分的区别,但是那些坐在公司防火墙后面的可怜的数字处理人员仍然被迫使用过时的 IE 版本呢?如果所需的 DOM 操作更重,需要进行属性操作并积极地强制重新绘制/重新流动怎么办?

我要说的是,如果你想优化一些 javascript,这不是一个糟糕的起点。

于 2012-11-03T06:49:25.723 回答
0

我认为,如果你开始意识到这种代码是性能瓶颈,你应该使用模板而不是 DOM 操作。

但是,是的,使用文档片段方法(在附加到 DOM 之前将所有节点放入一个分离的节点)在大多数情况下会更快,几乎不会变慢。

于 2012-11-03T00:12:32.603 回答