为什么在附加documentFragment时需要使用cloneNode?

时间:2012-12-13 10:44:19

标签: javascript dom backbone.js documentfragment

我一直在查看在Backbone.js应用程序中使用documentFragments,并想知道为什么我看到在将documentFragment附加到父DOM元素时使用“cloneNode”的示例。

可以看到一个例子here。如果你低头看看DocumentFragment部分,你会看到:

oFrag = document.createDocumentFragment();
for (var i = 0, imax = aElms.length; i < imax; i++) {
 oFrag.appendChild(aElms[i]);
}

o.innerHTML = '';
o.appendChild(oFrag.cloneNode(true));

为什么“oFrag”被克隆而不是仅仅附加它?另一个blog post不使用“cloneNode”(作为比较)。

4 个答案:

答案 0 :(得分:7)

您的first link指的是blog post,其中autor使用document.getElementsByTagName代替document.getElementById,就像在测试用例中一样。如果您希望多个元素(即:div)被赋予相同的documentFragment,则必须克隆它:

  

如果child是对文档中现有节点的引用,则appendChild将其从当前位置移动到新位置(即,在将节点附加到其他节点之前不需要从其父节点中删除该节点)。

     

这也意味着节点不能同时位于文档的两个点。因此,如果节点已经有父节点,则首先删除它,然后将其附加到新位置。

通过MDN

作者(或其他人)很可能在不考虑这一点的情况下复制粘贴代码。自己尝试一下 - 你可以使用appendChild而不用cloneNode,一切正常。

另一种可能性是,在jsperf上创建此测试用例的人没有太多准备代码如何工作,并担心第一个测试将清空aElms数组,它将不再起作用。 In fact准备代码在每次定时迭代之前执行,因此无需担心其内容。

最后一件事可能是性能问题。如果您确实要测试实际插入,则需要克隆该节点。否则,您将测试树重新附加(请参阅上面的MDN链接)。

另请注意cloning destroys event listeners

快乐的片段'! ;)

答案 1 :(得分:2)

我不太确定,但是在您提供的链接(性能测试)的上下文中,oFrag.cloneNode(true)可能是一种防止在以前的循环运行中重用已经添加到DOM中的元素的保护措施。从而加快了测试的执行速度。

我认为没有理由在documentFragments的正常使用情况下使用它。

答案 2 :(得分:2)

如果将documentFragment附加到元素,并且稍后清除该元素中的附加节点,则documentFragment也将为空,并且不能再重复使用!附加documentFragment的克隆可以防止这种情况,并允许多次重复使用documentFragment。

我认为jsperf片段的作者正在测试这种情况。

示例:具有父子关系的下拉列表。假设您选择一个大陆的下拉列表,以及列出该大陆所有国家/地区的第二个下拉列表。如果要在创建后使用选项节点缓存创建的documentFragments,则必须使用cloneNode。想象一下有人选择欧洲,然后是非洲,再选择欧洲:你可以重新创建整个文档片段,缓存它。

我创建了一个jsperf片段来说明重新创建documentFragments与缓存和克隆片段的性能差异:

http://jsperf.com/documentfragment-cache-vs-recreate

答案 3 :(得分:0)

我认为没必要。我想这只是用于将aElms与静态引用分开,在调用appendChild时,他们需要从父母那里删除它们。它仅适用于此测试中的性能。

但是,以下代码(更类似于appendChild测试)对我来说更有意义:

var oFrag = document.createDocumentFragment();
for (var i = 0, imax = aElms.length; i < imax; i++)
    oFrag.appendChild(aElms[i].cloneNode(true));
// using it here:             ^^^^^^^^^^^^^^^^
o.appendChild(oFrag);

虽然它可能比在整个片段上只调用一次更慢,但是节点树是用本机代码递归的。

同时查看http://jsperf.com/cloning-fragments: - )