10

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

可以在这里看到一个例子。如果您低头查看 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”被克隆而不是仅仅附加它?另一篇博文没有使用“cloneNode”(作为比较)。

4

4 回答 4

7

您的第一个链接是指作者使用而不是的博客文章,例如在测试用例中。如果你想给多个元素(即:divs)赋予相同的,你必须克隆它:document.getElementsByTagNamedocument.getElementByIddocumentFragment

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

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

通过MDN

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

另一种可能性是,在 jsperf 上创建了这个测试用例的人并不太了解准备代码是如何工作的,并且担心第一个测试会清空aElms数组并且它不会再工作了。事实上,准备代码是在每次定时迭代之前执行的,所以不必担心它的内容。

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

另请注意,克隆会破坏事件侦听器

快乐的碎片化!;)

于 2012-12-13T11:22:33.337 回答
3

如果您将一个 documentFragment 附加到一个元素,然后您从该元素中清除了附加的节点,那么您的 documentFragment 也将是空的并且不能再被重用!附加您的 documentFragment 的克隆可以防止这种情况,并允许您的 documentFragment 多次重用。

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

Example: dropdowns with a parent-child relationship. Lets say you have a dropdown where you select a continent, and a second dropdown that lists all the countries in that continent. If you want to cache the created documentFragments with the option nodes after creation, using cloneNode is necessary. Imagine someone selects europe, then africa, then europe again: you can either recreate the entire documentfragment, of cache it.

I created a jsperf snippet to illustrate the performance difference of recreating the documentFragments vs caching and cloning the fragments:

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

于 2013-10-08T15:29:39.403 回答
2

我不太确定,但是在您提供的链接的上下文中(性能测试),这oFrag.cloneNode(true)可能是防止重复使用在循环的先前运行中已经添加到 DOM 中的元素的一种保护措施,这将导致更快地执行测试.

我认为没有理由在 documentFragments 的正常用例中使用它。

于 2012-12-13T11:04:55.570 回答
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 :-)

于 2012-12-13T11:05:05.147 回答