documentFragment - "фрагмент документа" наиболее близок по смыслу к обычному DOM-элементу.
То есть, его можно создать:
var fragment = document.createDocumentFragment()
в него можно добавлять другие узлы.
fragment.appendChild(node)
Фишка заключается в том, что когда documentFragment вставляется в DOM - то он исчезает, а вместо него вставляются его дети. Это единственное и основное свойство documentFragment по сравнению со всеми остальными сущностями DOM.
То есть, можно добавить в него много TD, и потом append к TR. При этом фрагмент растворится и вставятся именно TD как прямые потомки.
Первый случай, когда documentFragment применим - это возврат множества узлов из функции. Можно это сделать возвращением массива, а можно вернуть documentFragment:
function makeRow() {
var fragment = document.createDocumentFragment()
var td_1 = document.createElement('TD')
fragment.appendChild(td_1)
...
fragment.appendChild(td_n)
return fragment
}
Затем внешняя функция может вставить его в DOM или использовать далее без промежуточных массивов.
Допустим, нам нужно создать пачку элементов TR и вставить их в DOM.
Первый способ - создавать их и вставлять. И так n раз.
Но операция вставки в "живой" DOM дорогая. И тут на помощь приходит как раз documentFragment. Можно вставлять в него, а уже потом его добавить в DOM.
При этом скорость будет отличаться.
Совершенно не важно, используете ли вы в качестве оторванного от DOM контейнера documentFragment или что-то другое.
Важно, что промежуточные вставки идут в оторванный от живого документа DOM.
Например, вот два бенчмарка.
Оба они создают таблицу 10x10, наполняя TBODY элементами TR/TD.
При этом первый вставляет все в документ тут же, второй - задерживает вставку TBODY в документ до конца процесса.
Кликните, чтобы запустить.
/* appends elements right after creation */
appendFirst = new function() {
var benchTable
this.setup = function() {
benchTable = document.getElementById('bench-table')
while(benchTable.firstChild) { benchTable.removeChild(benchTable.firstChild) }
}
this.work = function() {
var tbody = document.createElement('TBODY')
benchTable.appendChild(tbody)
for(var i=0; i<10; i++) {
var tr = document.createElement('TR')
tbody.appendChild(tr)
for(var j=0; j<10; j++) {
var td = document.createElement('td')
td.appendChild(document.createTextNode(''+i+j))
tr.appendChild(td)
}
}
}
}
/* appends elements right after creation
BUT wrapping tbody appended late */
appendLast = new function() {
var benchTable
this.setup = function() {
benchTable = document.getElementById('bench-table')
while(benchTable.firstChild) { benchTable.removeChild(benchTable.firstChild) }
}
this.work = function() {
var tbody = document.createElement('TBODY')
for(var i=0; i<10; i++) {
var tr = document.createElement('TR')
tbody.appendChild(tr)
for(var j=0; j<10; j++) {
var td = document.createElement('td')
tr.appendChild(td)
td.appendChild(document.createTextNode(''+i+j))
}
}
benchTable.appendChild(tbody)
}
}
При чем же здесь documentFragment? А не при чем! Вместо него может быть любой узел, но иногда удобен именно documentFragment из-за своего свойства растворяться при вставке.
То есть, когда неудобно делать промежуточный узел-контейнер, например при добавлении множества TR, подгруженных с сервера. Вместо n вызовов appendChild в живой DOM имеем только 1 вызов, это может дать экономию такую же как в бенчмарках выше.
Фрагмент документа ничего не оптимизирует сам по себе, он не быстрее обычного документа.
Оптимизация заключается именно в том, что все действия делаются вне DOM.
Но благодаря свойству растворяться при вставке, documentFragment уникален, и его стоит иметь в виду. Не всегда можно и удобно создавать настоящий контейнер, а такой, временный - может очень даже пригодиться.
Спасибо за статью, раньше не знал про фрагменты.
Сейчас бегло прошёлся поиском по исходникам jQuery - фрагменты используются довольно активно. Так что могу предположить, что при использовании jQuery можно не беспокоиться о скорости вставки элементов.
Спасибо за статью, раньше не знал про фрагменты.
Сейчас бегло прошёлся поиском по исходникам jQuery - фрагменты используются довольно активно. Так что могу предположить, что при использовании jQuery можно не беспокоиться о скорости вставки элементов.
В тексте, который ниже бенчмарка три раза повторяется одно и то же. Прошу прощения, что комментарий не по сути.
Что-то у меня в хроме иногда первый бенчмарк (без фрагментов) быстрее второго
Привет
Попробовал два теста. Оба выдали по 11. Что я должен был увидеть?
Браузер - Chrome на Mac OS X.
Спасибо.
Firefox 27, Pentium 4 3.06GHz.
Неотложенный в среднем 19 мс.
Отложенный в среднем 11 мс.
Chrome 34.0.1847.137
Оба теста одинаково перформят
можно из полученного (например ajax-ом) куска html сразу получить documentFragment
Непосредственная - 5
Отложенная - 4
Firefox на OS X - MacBook Pro
Google Chrome на OS X Mavericks:
Непосредственная - 6
Отложенная - 3
Фишка заключается в том, что когда documentFragment вставляется в DOM - то он исчезает, а вместо него вставляются его дети.
творяться при вставке, documentFragment уникален, и его стоит иметь в виду. Не всегда можно и удо