【问题标题】:Why does cloneNode need to be used when appending a documentFragment?为什么附加documentFragment时需要使用cloneNode?
【发布时间】:2013-10-09 19:42:26
【问题描述】:

我一直在研究在 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”(作为比较)。

【问题讨论】:

  • +1,确实很有趣。我唯一(而且非常疯狂)的猜测是 cloneNode 的使用使我们能够更好地控制 oFrag 范围。
  • 我认为这不应该被伪造成一个完整的答案,但无论如何......只需寻找'documentFragment cloneNode',我就找到了John Resig 的this post。 ) 在这篇文章的主题中,应该将一堆节点插入到 DOM 中几次次,因此克隆 documentFragment 确实是一个更好的选择。

标签: javascript dom backbone.js documentfragment


【解决方案1】:

您的first link 指的是blog post,其中作者使用document.getElementsByTagName 而不是document.getElementById,就像在测试用例中一样。如果你想给多个元素(即:divs)赋予相同的documentFragment,你必须克隆它:

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

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

通过MDN

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

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

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

另外请注意cloning destroys event listeners

快乐的碎片化! ;)

【讨论】:

    【解决方案2】:

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

    我假设 jsperf sn-p 的作者正在测试这种情况。

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

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        我认为没有必要。我猜它只是用于将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 :-)

        【讨论】:

          猜你喜欢
          • 2021-05-08
          • 1970-01-01
          • 1970-01-01
          • 2013-08-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-01
          • 1970-01-01
          相关资源
          最近更新 更多