Получил это от https://developers.google.com/speed/articles/javascript-dom
Из того, что я понимаю, добавление/удаление элементов вызывает оплату. Как и изменение класса. Но в решении вы добавляете и удаляете, таким образом, вызывая в два раза количество переходов как проблемный код. Конечно, не все коэффициенты пересчета равны, поэтому изменение имени класса переплачивает более дорого, чем добавление/удаление перерасчетов? Что мне не хватает, что делает код решения более эффективным, чем код проблемы?
Этот шаблон позволяет нам создавать несколько элементов и вставлять их в DOM, запуская один возврат. Он использует что-то, называемое DocumentFragment. Мы создаем DocumentFragment вне DOM (так что это вне потока). Затем мы создаем и добавляем к нему несколько элементов. Наконец, мы перемещаем все элементы в DocumentFragment в DOM, но запускаем один возврат.
Проблема
Позвольте сделать функцию, которая изменяет атрибут className для всех якорей внутри элемента. Мы могли бы сделать это, просто повторяя каждый якорь и обновляя атрибуты href. Проблемы в том, что это может привести к перепланировке для каждого якоря.
function updateAllAnchors(element, anchorClass) { var anchors = element.getElementsByTagName('a'); for (var i = 0, length = anchors.length; i < length; i ++) { anchors[i].className = anchorClass; } }
Решение
Чтобы решить эту проблему, мы можем удалить элемент из DOM, обновить все привязки и затем вставить элемент туда, где он был. Чтобы помочь в этом, мы можем написать функцию многократного использования, которая не только удаляет элемент из DOM, но также возвращает функцию, которая вернет элемент обратно в исходное положение.
/** * Remove an element and provide a function that inserts it into its original position * @param element {Element} The element to be temporarily removed * @return {Function} A function that inserts the element into its original position **/ function removeToInsertLater(element) { var parentNode = element.parentNode; var nextSibling = element.nextSibling; parentNode.removeChild(element); return function() { if (nextSibling) { parentNode.insertBefore(element, nextSibling); } else { parentNode.appendChild(element); } }; }
Теперь мы можем использовать эту функцию для обновления привязок в элементе, который находится вне потока, и только инициировать оплату при удалении элемента и при вставке элемента.
function updateAllAnchors(element, anchorClass) { var insertFunction = removeToInsertLater(element); var anchors = element.getElementsByTagName('a'); for (var i = 0, length = anchors.length; i < length; i ++) { anchors[i].className = anchorClass; } insertFunction(); }
Предположим, вы хотите изменить классы из 1 миллиона элементов.
Выполнение этого непосредственно вызовет 1 миллион переходов -one для каждого class-.
Но если вы удалите его родителя из DOM, измените все классы и вставьте его обратно, то только 2 reflows -because, изменяющие элементы за пределами документа, не вызывают reflow-.
Поэтому, в основном, удаление и повторное вложение более эффективно, если у вас много элементов. Не нужно это делать, если у вас есть только несколько.
Согласно решению:
Чтобы решить эту проблему, мы можем удалить элемент из DOM, обновить все привязки и затем вставить элемент туда, где он был.
Таким образом, в этом случае он вызывает два переплава (один для удаления и один для вставки). Таким образом, это решение применяется, если вы хотите изменить более двух элементов одновременно.
Таким образом, фрагмент документа живет "в памяти", а не на странице. Манипулирование этим не вызывает каких-либо повторов/потоков, потому что фрагмент визуально не представлен нигде. Когда вы положите его на страницу, как только вы закончите манипулировать им, браузер узнает о его структуре, классах, контенте и т.д., Поэтому нужно будет только перепроверять/рисовать один раз.
В первом примере, когда вы зацикливаете анкеры и меняете имя класса (предположительно меняя его стиль), он немедленно применит этот класс, найдет новый стиль и перекрасит эту ссылку. Затем сделайте то же самое для следующего. Это медленно.
Вытаскивая все это в память и манипулируя DOM там, у вас есть только один перерисовка/поток, когда вы снова вставляете элемент родительской оболочки в страницу.