“虚拟”dom操纵?

时间:2012-11-02 23:34:59

标签: javascript jquery dom dom-manipulation

我知道做多次dom操作很糟糕,因为它会强制多次重绘。

即:

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

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

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

但我对虚拟操作感到好奇

即:

$('<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 个答案:

答案 0 :(得分:10)

首先,虽然很好地阅读这样的潜在性能命中,但您应该始终先测量一下,看看是否有问题。

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

如果您能感知到问题,请进行测量,更改和测量。

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

如果能够捕捉到第二个和第三个例子之间的速度差异,我会非常惊讶 - 如果你能看到它们之间有任何重大差异,我会感到非常惊讶。

答案 1 :(得分:1)

如果您在添加节点时真的担心性能,则需要使用documentfragments。这些将允许您将元素附加到dom而不重新绘制。 John Resign在此主题上有一个excellent article。他指出,性能提升了200-300%。我在我的一个应用程序中实现了文档碎片,并可以确认他的声明。

答案 2 :(得分:1)

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

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

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

这对我的设置来说是一个难以区分的差异,但是那些坐在公司防火墙后面的数字拙劣的人仍然被迫使用过时的IE版本呢?如果所需的DOM操作更重,具有属性操作和积极强制re-paints/re-flows怎么办?

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

答案 3 :(得分:0)

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

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