Удалить все дочерние узлы в 0 (1) в элементе DOM - PullRequest
2 голосов
/ 05 марта 2019

При взгляде на childNodes parentNode структура данных выглядит как массив, похожий на объект.

Вместо того, чтобы перебирать каждый дочерний узел и удалять его - возможно ли просто удалить массивоподобный объект?

Я думаю о производительности здесь и хотел бы избежать перебора дочерних элементови удаляя их по одному.

В моем случае я создаю дочерние элементы Li на родительском элементе Ul:

  _createLi(address) {
    const parentUl = document.querySelector("ul#parent");
    const li = document.createElement("li");
    li.appendChild(document.createTextNode(address));
    parentUl.appendChild(li);
  }

Я могу удалить их следующим образом:

  _removeLi(node) {
    while (!node.lastChild) node.removeChild(!node.lastChild);
  }

Это работает, ноон проходит через каждый узел.Как удалить все дочерние узлы, удалив объект, такой как массив, который их содержит, и возможно ли это в O (1)?

Ответы [ 2 ]

2 голосов
/ 05 марта 2019

Обновление

Быстрее, чем .cloneNode() и .replaceChild()

Диапазон API

На 5% быстрее, чем ВСЕ примеры
(включая принятый ответ)

Следующий пример взят из Range API :

const rng = document.createRange();
rng.selectNodeContents(document.querySelector('ul'));
rng.deleteContents();

интерфейс Range работает с фрагментами документа, которые содержат узлы и текст.Хотя выглядит медленным , на самом деле это быстро и 100% совместимо со всеми браузерами .

Методы диапазона

.createRange()
.selectNodeContents()
.deleteContents()


.replaceWith() и .createElement()

15% медленнее, чем все примеры
Эта комбинация быстрее, чем большинство примеров, и менее многословна (за исключением демонстрации Range , являющейся самой быстрой.)

 document.querySelector('ul').replaceWith(document.createElement('ul'));

Это 2 взаимодействия DOM:Найдите список и замените его пустым списком.См. Демонстрацию 1. Если вы хотите поддерживать IE11 (глобальная доля ATM 2,26%) , не используйте его.


Демо 1

Range API

const rng = document.createRange();
rng.selectNodeContents(document.querySelector('ul'));
rng.deleteContents();
ul {
  min-height: 30px;
  min-width: 30px;
  outline: 1px dashed red;
}
<ul>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
</ul>

Демо 2

.replaceWith() и .createElement()

document.querySelector('ul').replaceWith(document.createElement('ul'));
ul {
  min-height: 30px;
  min-width: 30px;
  outline: 1px dashed red;
}
<ul>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
</ul>

.insertAdjacentHTML() & .createDocumentFragment()

@ 50% медленнее, чем все примеры
Лучший способ оптимизировать любые манипуляции с DOM - это не иметь их.Держите доступ DOM к минимуму - это очень много времени.Каждый раз, когда механизм JS ищет элемент, он будет проходить по дереву DOM, каждый раз, когда тег добавляется или удаляется, узлы (элемент, текст и т. Д.), Которые уже находятся в DOM, должны пересчитываться для определения местоположения и размеров, чтобы дажеесли количество задействованных узлов всего несколько, это может привести к исключительно длительному процессу для браузера.Это называется reflow, а похожая проблема, связанная со стилями CSS, называется перерисовкой.


Следующая демонстрация удаляет все <li> в <ul> с 4 операциями DOM:
  1. Ссылка на <ul> - 1 поиск

  2. Ссылочный родительский элемент <ul> добавляет пустой <ul> - 1 поиск, 1 добавление

  3. Создать documentFragment и добавить к нему оригинал <ul> - 1 удаление

.insertAdjacentHTML() рендеринг неразрушающим образом htmlString в HTML и он высоко оптимизирован .

.createDocumentFragment() никогда не касается DOM и все, что к нему прикреплено, больше не касается DOM.


Демонстрация 3

.insertAdjacentHTML и .createDocumentFragment()

// Reference the <ul>
const list = document.querySelector('ul');

// Reference parent of <ul> append an empty <ul>
list.parentElement.insertAdjacentHTML('beforeend', `<ul></ul>`);

// Create a document fragment and append original <ul> to it
document.createDocumentFragment().appendChild(list);
ul {
  min-height: 30px;
  min-width: 30px;
  outline: 1px dashed red;
}
<ul>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
  <li>ITEM</li>
</ul>
2 голосов
/ 05 марта 2019

Я действительно сомневаюсь, что потомков можно удалить в O (1), даже с node.innerHTML = '', так как базовая реализация вполне может быть операцией O (N).

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

  1. Вы можете попробовать заменить элемент на клон.

const list = document.querySelector('ul');
const listClone = list.cloneNode(false);
list.parentNode.replaceChild(listClone, list);
<ul>
  <li>First</li>
  <li>Last</li>
</ul>
Вы можете попробовать удалить список из DOM, выполнить манипуляции и добавить его обратно.

withElOutOfFlow(document.querySelector('ul'), el => {
   while(el.lastChild) el.removeChild(el.lastChild);
});

function withElOutOfFlow(el, callback) {
  const parent = el.parentNode;
  
  if (!parent) {
    callback(e);
    return;
  }
  
  const nextSibling = el.nextSibling;
  parent.removeChild(el);
  callback(el);
  
  if (nextSibling) parent.insertBefore(el, nextSibling);
  else parent.appendChild(el);
}
<ul>
  <li>First</li>
  <li>Last</li>
<ul>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...