Почему cloneNode необходимо использовать при добавлении documentFragment?
Я смотрел на использование documentFragments в приложении Backbone.js, и мне было интересно, почему я вижу примеры, где "cloneNode" используется при добавлении documentFragment к родительскому элементу DOM.
Пример можно увидеть здесь. Если вы посмотрите вниз на раздел 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 ответа
Ваша первая ссылка относится к сообщению в блоге, где автор использует document.getElementsByTagName
вместо document.getElementById
, как в тестовом случае. Если вы хотите, чтобы несколько элементов (а именно: div) были заданы одинаково documentFragment
Вы должны клонировать это:
Если child является ссылкой на существующий узел в документе, appendChild перемещает его из своей текущей позиции в новую позицию (то есть нет необходимости удалять узел из его родительского узла перед добавлением его в какой-либо другой узел).
Это также означает, что узел не может находиться в двух точках документа одновременно. Поэтому, если узел уже имеет родителя, он сначала удаляется, а затем добавляется в новой позиции.
через MDN
Скорее всего, автор (или кто-то еще) скопировал код, не принимая это во внимание. Попробуйте сами - вы можете использовать appendChild
без cloneNode
и все работает отлично.
Другая возможность состоит в том, что тот, кто создал этот тестовый пример на jsperf, не очень понимал, как работает подготовительный код, и беспокоился, что самый первый тест опустеет. aElms
массив, и он больше не будет работать. На самом деле подготовительный код выполняется перед каждой временной итерацией, поэтому нет необходимости беспокоиться о его содержимом.
Последнее, что может касаться производительности. Если вы действительно хотите проверить настоящую вставку, вам нужно клонировать узел. В противном случае вместо этого вы будете тестировать присоединение дерева (см. Ссылку MDN выше).
Также обратите внимание, что клонирование уничтожает слушателей событий.
Счастливый фрагмент!;)
Если вы добавляете documentFragment к элементу и позже удаляете добавленные узлы из этого элемента, ваш documentFragment также будет пустым и больше не будет использоваться повторно! Добавление клона вашего documentFragment предотвращает это и позволяет многократно использовать ваш documentFragment.
Я предполагаю, что автор фрагмента jsperf тестировал для такого случая.
Пример: раскрывающиеся списки с отношениями родитель-ребенок. Допустим, у вас есть выпадающий список, в котором вы выбираете континент, и второй выпадающий список, в котором перечислены все страны этого континента. Если вы хотите кэшировать созданные фрагменты документа с помощью узлов параметров после создания, необходимо использовать cloneNode. Представьте, что кто-то выбирает Европу, затем Африку, затем Европу снова: вы можете воссоздать весь фрагмент документа, кэшируя его.
Я создал фрагмент jsperf, чтобы проиллюстрировать разницу в производительности при воссоздании documentFragments и кешировании фрагментов:
Я не совсем уверен, но в контексте ссылки, которую вы предоставили (тестирование производительности) oFrag.cloneNode(true)
может быть защитой от повторного использования элементов, уже добавленных в DOM в предыдущих запусках цикла, что приведет к более быстрому выполнению теста.
Я не вижу смысла использовать его в обычных случаях использования documentFragments.
Я не думаю, что это необходимо. Я думаю, это было использовано только для отделения 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:-)