Как я могу ускорить добавление большого количества сложного HTML в DOM

У меня есть простая веб-страница, которая загружает большую часть контента через вызов AJAX, который возвращает большое количество сложного HTML. Когда я помещаю извлеченный HTML-код в DOM, он довольно долго портит браузер (от 5 секунд в Chrome до 35 секунд в Edge).

Пример того, как я добавляю HTML в DOM:

$.ajax("example.php").done(function (response) {
    const contentElement = document.getElementById('results');
    contentElement.innerHTML = response;
});

Я хочу избежать необходимости возвращать JSON и преобразовывать его в HTML любой ценой из-за сложности приложения.

Странно то, что браузер немного теряет силу после того, как вставленный HTML уже виден. Посмотрите временную шкалу ниже, где я могу увидеть HTML на моем экране (с надлежащим стилем) до того, как произойдут события Parse HTML продолжительностью ~5 секунд.

Сроки исполнения

Как ускорить разбор и добавление HTML в DOM?

Редактировать: я пробовал несколько браузеров и несколько способов внедрения HTML (documentFragments, innerHTML, jquery .html(), append()). Все методы примерно такие же медленные.

Edit2: точный введенный HTML можно увидеть в этом гисте: https://gist.github.com/Rhinni/3032e74bab0de8f40e08a3392c0243b1

3 ответа

Решение

Я исправил проблему с помощью ответов Trevor и Zer00ne, но это было нечто совершенно другое.

Проблема была вызвана отладочной панелью Laravel, которая по умолчанию отслеживает запросы AJAX и анализирует ответ для целей отладки. Отключение отслеживания AJAX-запросов в конфигурации Debugbar решило проблему.

Часть 1 - Код загружается не так, просто код недействителен и не будет работать, даже если он жестко задан на странице.


"Странно то, что браузер немного поврежден после того, как вставленный HTML-код уже виден. Смотрите временную шкалу ниже, где я могу увидеть HTML-код на моем экране (с надлежащим стилем) до того, как произойдут события Parse HTML длиной ~ 5 секунд.".


Есть некоторые вещи, которые должны быть рассмотрены в отношении практичности HTML (его нелепость говорит сама за себя), его валидности (чего не происходит) и функциональности (чего у него нет и, вероятно, никогда не было).

Вы должны проверить свой HTML, потому что он очень недействительный, но прежде чем мы начнем проверять этот беспорядок, вам нужно будет разделить его на 16 частей, потому что большинство онлайн-сервисов рано или поздно прекратят процесс проверки, если учитывая, что много для обработки за один раз.

Ниже приведен список проблем, которые не являются изолированными проблемами из-за опечатки. Эти проблемы повторяются несколько раз. Больше всего меня беспокоит то, что значения и большинство переменных, похоже, настраиваются вручную. Надеюсь, я ошибаюсь, и вы не тратили часы на настройку значений, которые будут мешать, а не будут иметь какое-либо реальное применение.


1. #ID s должны быть уникальными - ни при каких обстоятельствах не должно быть дубликатов # ID на той же странице.


14 #accordion - фиксированная, 14 #headingOne - фиксированная, 7 #model 7 #type 7 #brand,...

Там больше обманут #ID с, я изменил #accordion в #acordion 1 до 14, потому что это было необходимо для каждого #accordion функционировать, а не только первый. Все связанные атрибуты, которые напрямую связаны с #accordion нужно изменить, мне удалось изменить toggle-parent="#accodion ради функциональности еще раз. Итак, есть 15 действующих аккордеонов, я добавил вкладку Home с правильно разработанным аккордеоном, который вы можете использовать в качестве шаблона, если решите изменить дизайн остальных 14 аккордеонов.


2. Чтобы использовать компоненты Bootstrap, вы делаете их в соответствии с документом.


Код OP даже не был близок к наличию каких-либо вкладок, если вы ссылались на документы Bootstrap или даже на короткие учебники W3School, вы бы знали, что вам необходимо иметь <a> для каждой вкладки, поэтому ваш код не хватает 16 <a> переключать 16 вкладок. Вот почему на вашей странице отображается только первая вкладка из 16 вкладок, а не потому, что браузер просто не работает на полпути.

3. Еще одна недействительная вещь, которую я заметил, это то, что атрибут readonly (а также required в меньшей степени) применялся практически к каждому виду контроля.


Зачем вам нужен readonly атрибут на <select> тег? При назначении атрибутов элементам, не начинайте добавлять тонну атрибутов ко всему. Беспорядок делает невозможным чтение, обслуживание и отладку.


4. Есть 2 Plunks:


  1. Планка 1 является решением вопроса OP (Oginginal P ost), который подробно объясняется во второй части этого ответа. HTML был частично исправлен, мне не хватает времени, чтобы все исправить.

  2. Он имеет 16 вкладок и 15 аккордеонов, которые работают.

  3. Время загрузки уменьшено с 34 до 2 секунд. с краю. Похоже, что Edge героически пытается разобраться в HTML, который был проанализирован, а затем потерпел неудачу. Реальные браузеры, такие как Firefox и Chrome, просто сбрасывают его и оставляют там.

  4. Plunk 2 - это HTML-код из кода OP, и мое решение загружает его.

  5. Результаты одинаковы, код OP дает сбой из-за самого кода, а не из-за проблемы загрузки.


Часть 2 - стабильный способ разбора огромной строки в HTML. Не требуется, если код OP действительно работает.


OP испытывает большие задержки при попытке добавить огромное количество разметки в DOM innerHTML, До 34 секунд, чтобы сделать его полностью, используя Edge, в то время как другие браузеры OP сообщили о 3 секундах.

Я сократил время загрузки до 2–3 секунд в Edge и сразу в реальных браузерах (Chrome и Firefox).

Хотя OP уже пытался использовать createDocumentFragment(), я считаю, что это ключ к быстрой загрузке и анализу указанного HTML. Другими ключевыми компонентами, которые OP, вероятно, не использовал, являются: insertAdjacentHTML () и выражение немедленного вызова функции

С помощью insertAdjacentHTML() метод вместо innerHTML имущество. insertAdjacentHTML() это мощная и универсальная версия innerHTML,

сходства:

  • Оба будут принимать данную строку и анализировать как HTML.

  • Оба быстрые.

Отличия:

insertAdjacentHTML() вставляет HTML в DOM, он не перезаписывает какой-либо существующий HTML в элементе или в любом месте DOM. innerHTML перезаписывает внутреннюю часть элемента.

innerHTML направляется ссылкой на элемент, для которого он будет принимать строку и перезаписывать все содержимое указанного элемента данной строкой. Если innerHTML просто направляется на элемент без строки, затем возвращается с HTML-содержанием указанного элемента. innerHTML способность получать - это единственное insertAdjacentHTML() это не может сделать. По сравнению, insertAdjacentHTML() Способность к установке мощна, как объяснено: insertAdjacentHTML() направляется не только ссылкой на элемент, но и точно указывается, куда идти по отношению к элементу, на который ссылаются, его первым параметром, который является одной из 4 строк DOMStrings, которые соответствуют позиции:

"beforebegin" помещает строку прямо перед началом элемента.

      `$elector.before(str)`★

"afterend" помещает строку сразу после конца элемента.

      `$elector.after(str)`★

"afterbegin" помещает строку в элемент сразу после окончания строки. Другими словами, строка вставляется перед содержимым элемента.

     `$elector.prepend(str)`★

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

     `$elector.append(str)`★

insertAdjacentHTML()Второй параметр - это строка, которая будет проанализирована в HTML. Использование литералов шаблона вместо строковых литералов позволяет нам получить дополнительный уровень легкой работы со строками.

    `element.insertAdjacentHTML("beforeend", <input id="${ID+i}" type="${typeArr[i]}" value="${Math.floor(Math.random() * i}">)`

Выражение с немедленным вызовом функции - это функция со специальным шаблоном.

  • Обычно это две анонимные функции:

  • Внешняя функция заключена в круглые скобки.

  • Внутренняя функция обычно образует замыкание.

  • Функции анонимных выражений создаются при оценке, а затем они немедленно вызываются из-за дополнительных скобок, заключенных вокруг них.

  • У них нет имени, и переменные, которые использует внутренняя функция, могут быть доступны только внешней функции, потому что они являются локальной областью действия.

Эти условия делают IIFE одноразовой вещью. Подпись IIFE имеет небольшие отклонения в своей подписи, но суть одного выглядит так:

`(function() { var x = function() {...} x})();`

Манипулирование DOM требует интенсивной работы процессора, и чем больше мы этого избегаем, тем лучше. DocumentFragment Это было сделано для того, чтобы мы выполнили все простые, но многочисленные задачи, связанные с DOM - от DOM. Мы можем добавить столько элементов, текста, атрибутов, установить обработчики событий и т. Д. В DocumentFragment и его потомков, не касаясь DOM. Когда все завершено, нужно выполнить только одну операцию DOM:

 `document.body.appendChild(frag);` 

Демо-версия - если вы хотите протестировать действующую демоверсию, просмотрите этот Plunk

<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8'>
  <title>Monstrosity</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
</head>

<body>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.min.js"></script>
  <script>
    (function() {
      const str = `Huge Disaster of HTML`
      const frag = document.createDocumentFragment();
      const node = document.createElement('div');
      let build = function(node, str, frag) {
        node.insertAdjacentHTML('beforeend', str);
        frag.appendChild(node);
        document.body.appendChild(frag);
      }
      build(node, str, frag);
    }());
  </script>
</body>

</html>

Простое добавление или вставка HTML-кода, предоставленного вами в браузер, похоже, не оказывает негативного влияния. По крайней мере, для меня в моем браузере / компьютере. (хром)

Запустите этот пример и посмотрите, есть ли у вас какие-либо задержки или паузы.

См пример

    document.getElementById("test").innerHTML = toAppend;

Очевидно, что это не полный тест, потому что мне не хватает вашего CSS, и я немного изменил ваш HTML, удалив разрывы строк, чтобы я мог назначить текст переменной в текстовом редакторе.

Если пример работает для вас, тогда нам нужно дополнительно изучить данные, поступающие с сервера, и попытаться добавить css в уравнение и т. Д.

Если пример вызывает задержки, то проблема, вероятно, связана с аппаратным обеспечением, возможно, у вас недостаточно доступной памяти и / или процессора, который наносит вред браузеру.

Другие вопросы по тегам