$cache[$key] = empty($arr) ? NULL : $arr; return $cache[$key]; } // 门户 获取需要在频道显示的栏目主题数据 function portal_channel_thread($fid) { global $forumlist; if (empty($fid)) return NULL; $orderby = array('tid' => 1); $page = 1; // 遍历所有在频道显示内容的栏目 $category_forumlist = channel_category($fid); $arrlist = array(); $forum_tids = array(); $tidlist = array(); if ($category_forumlist) { foreach ($category_forumlist as &$_forum) { // 频道显示数据 $arrlist['list'][$_forum['fid']] = array( 'fid' => $_forum['fid'], 'name' => $_forum['name'], 'rank' => $_forum['rank'], 'type' => $_forum['type'], 'url' => $_forum['url'], 'channel_new' => $_forum['channel_new'], ); $forum_thread = thread_tid__find(array('fid' => $_forum['fid']), $orderby, $page, $_forum['channel_new'], 'tid', array('tid')); // 最新信息按栏目分组 foreach ($forum_thread as $key => $_thread) { $forum_tids[$key] = $_thread; } unset($forum_thread); } $tidlist += $forum_tids; } unset($category_forumlist); // 获取属性对应的tid集合 list($flaglist, $flagtids) = flag_thread_by_fid($fid); empty($flagtids) || $tidlist += $flagtids; unset($flagtids); // 频道置顶 $stickylist = sticky_list_thread($fid); empty($stickylist) || $tidlist += $stickylist; // 在这之前合并所有二维数组 tid值为键/array('tid值' => tid值) $tidarr = arrlist_values($tidlist, 'tid'); // 在这之前使用$tidarr = array_merge($tidarr, $arr)前合并所有一维数组 tid/array(1,2,3) if (empty($tidarr)) { $arrlist['list'] = isset($arrlist['list']) ? array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid') : array(); return $arrlist; } $tidarr = array_unique($tidarr); $pagesize = count($tidarr); // 遍历获取的所有tid主题 $threadlist = well_thread_find_asc($tidarr, $pagesize); // 遍历时为升序,翻转为降序 $threadlist = array_reverse($threadlist); foreach ($threadlist as &$_thread) { // 各栏目最新内容 isset($forum_tids[$_thread['tid']]) AND $arrlist['list'][$_thread['fid']]['news'][$_thread['tid']] = $_thread; // 全站置顶内容 isset($stickylist[$_thread['tid']]) AND $arrlist['sticky'][$_thread['tid']] = $_thread; // 首页属性主题 if (!empty($flaglist)) { foreach ($flaglist as $key => $val) { if (isset($val['tids']) && in_array($_thread['tid'], $val['tids'])) { $arrlist['flaglist'][$key][array_search($_thread['tid'], $val['tids'])] = $_thread; ksort($arrlist['flaglist'][$key]); $arrlist['flag'][$_thread['tid']] = $_thread; } } } } unset($threadlist); if (isset($arrlist['sticky'])) { $i = 0; foreach ($arrlist['sticky'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flag'])) { $i = 0; foreach ($arrlist['flag'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flaglist'])) { foreach ($arrlist['flaglist'] as &$val) { $i = 0; foreach ($val as &$v) { ++$i; $v['i'] = $i; } } } isset($arrlist['list']) AND $arrlist['list'] = array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid'); return $arrlist; } ?>javascript - Why does cloneNode need to be used when appending a documentFragment? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why does cloneNode need to be used when appending a documentFragment? - Stack Overflow

programmeradmin0浏览0评论

I've been looking at using documentFragments in a Backbone.js app and was wondering why I see examples where "cloneNode" is used when appending the documentFragment to the parent DOM element.

An example can be seen here. If you look down at the DocumentFragment section you'll see this:

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

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

Why does "oFrag" get cloned instead of just appending it? Another blog post doesn't use "cloneNode" (as a comparison).

I've been looking at using documentFragments in a Backbone.js app and was wondering why I see examples where "cloneNode" is used when appending the documentFragment to the parent DOM element.

An example can be seen here. If you look down at the DocumentFragment section you'll see this:

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

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

Why does "oFrag" get cloned instead of just appending it? Another blog post doesn't use "cloneNode" (as a comparison).

Share Improve this question asked Dec 13, 2012 at 10:44 codecraigcodecraig 3,15811 gold badges51 silver badges63 bronze badges 2
  • +1, very interesting indeed. My only (and quite wild) guess is that cloneNode usage gives us better control over oFrag scope. – raina77ow Commented Dec 13, 2012 at 11:03
  • I don't think this deserves to be forged into a full answer, but anyway... Simply by looking for 'documentFragment cloneNode' I've found this post of John Resig. ) In this post's topic a bunch of nodes should be inserted into DOM several times, thus cloning documentFragment is indeed a better choice. – raina77ow Commented Dec 13, 2012 at 11:12
Add a comment  | 

4 Answers 4

Reset to default 7

Your first link refers to the blog post where the autor uses document.getElementsByTagName instead of document.getElementById, like in test case. If you want a multiple elements (namely: divs) to be given the same documentFragment, you must clone it:

If child is a reference to an existing node in the document, appendChild moves it from its current position to the new position (i.e. there is no requirement to remove the node from its parent node before appending it to some other node).

This also means that a node can't be in two points of the document simultaneously. So if the node already has a parent, it is first removed, then appended at the new position.

via MDN

Most likely the author (or someone else) copy-pasted the code without taking this into consideration. Try it yourself - you can use appendChild without cloneNode and everything works fine.

Another possibility is that someone who created this test case on jsperf didn't get much how preparation code works and was worried that the very first test will empty aElms array and it won't work anymore. In fact preparation code is executed before each timed iteration, so there's no need to be worried about its contents.

The last thing may the performance concern. If you really want to test the real insertion, you need to clone the node. Otherwise, you'll test tree reattachment instead (see MDN link above).

Also please note that cloning destroys event listeners.

Happy fragmentin'! ;)

If you append a documentFragment to an element, and you later clear the appended nodes from that element, your documentFragment will also be empty and cannot be reused anymore! Appending a clone of your documentFragment prevents this and allows multiple reuses of your documentFragment.

I assume the author of the jsperf snippet was testing for such a case.

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

I'm not exactly sure, but in the context of the link you provided (performance testing) the oFrag.cloneNode(true) might be a safeguard against reusing the elements already added in DOM in previous runs of the loop, which would result in way faster execution of the test.

I see no reason to use it in normal use cases of documentFragments.

I don't think it's necessary. I guess it only was used to detach the aElms from being statically referenced, where they would've need to be removed from their former parents when calling appendChild. It's only for performance in this test.

However, the following code (more similar to the appendChild test) would make more sense to me:

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);

Though it might be slower than calling it only once on the whole fragment, where the node tree is recursed with native code.

Also check out http://jsperf.com/cloning-fragments :-)

发布评论

评论列表(0)

  1. 暂无评论