Манипуляция DOM вне потока

0

Получил это от 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();
}
Теги:
dom

3 ответа

2
Лучший ответ

Предположим, вы хотите изменить классы из 1 миллиона элементов.

Выполнение этого непосредственно вызовет 1 миллион переходов -one для каждого class-.

Но если вы удалите его родителя из DOM, измените все классы и вставьте его обратно, то только 2 reflows -because, изменяющие элементы за пределами документа, не вызывают reflow-.

Поэтому, в основном, удаление и повторное вложение более эффективно, если у вас много элементов. Не нужно это делать, если у вас есть только несколько.

1

Согласно решению:

Чтобы решить эту проблему, мы можем удалить элемент из DOM, обновить все привязки и затем вставить элемент туда, где он был.

Таким образом, в этом случае он вызывает два переплава (один для удаления и один для вставки). Таким образом, это решение применяется, если вы хотите изменить более двух элементов одновременно.

1

Таким образом, фрагмент документа живет "в памяти", а не на странице. Манипулирование этим не вызывает каких-либо повторов/потоков, потому что фрагмент визуально не представлен нигде. Когда вы положите его на страницу, как только вы закончите манипулировать им, браузер узнает о его структуре, классах, контенте и т.д., Поэтому нужно будет только перепроверять/рисовать один раз.

В первом примере, когда вы зацикливаете анкеры и меняете имя класса (предположительно меняя его стиль), он немедленно применит этот класс, найдет новый стиль и перекрасит эту ссылку. Затем сделайте то же самое для следующего. Это медленно.

Вытаскивая все это в память и манипулируя DOM там, у вас есть только один перерисовка/поток, когда вы снова вставляете элемент родительской оболочки в страницу.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню