У меня есть веб-страница на моем сайте, которая отображает таблицу, перезагружает исходные данные XML каждые 10 секунд (с помощью XmlHttpRequest), а затем обновляет таблицу, чтобы показать пользователю любые добавления или удаления данных. Для этого функция JavaScript сначала очищает все элементы таблицы, а затем добавляет новую строку для каждой единицы данных.
Недавно я столкнулся с рядом утечек памяти в Internet Explorer, вызванных этим кодом уничтожения и создания DOM (большинство из них связано с циклическими ссылками между объектами JavaScript и объектами DOM и библиотекой JavaScript, которую мы используем спокойно хранить ссылку на каждый объект JS, созданный с помощью new Element(...)
, до тех пор, пока страница не будет выгружена).
Решив проблемы с памятью, мы обнаружили проблему с процессором: когда у пользователя есть большой объем данных для просмотра (более 100 единиц данных, что равно 100 <tr>
узлам для создания плюс все ячеек таблицы для каждого столбца) процесс связывает ЦП до тех пор, пока Internet Explorer не предложит пользователю:
Прекратить запуск этого скрипта?
Сценарий на этой странице вызывает медленную работу Internet Explorer.
Если он продолжает работать, ваш компьютер может стать
отвечать на запросы.
Похоже, что выполнение кода создания строк и ячеек более 100 фрагментов данных вызывает скачкообразное использование ЦП, выполнение функции «слишком долго» (с точки зрения IE), что приводит к IE, чтобы сгенерировать это предупреждение для пользователя. Я также заметил, что хотя функция «обновления экрана» выполняется для 100 строк, IE не перерисовывает содержимое таблицы до тех пор, пока функция не завершит работу (так как я полагаю, что интерпретатор JS использует 100% ЦП для этого периода времени) .
Итак, мой вопрос: есть ли в JavaScript способ сказать браузеру приостановить выполнение JS и повторно отрендерить DOM? Если нет, существуют ли какие-либо стратегии для обработки создания большого количества DOM-узлов, а не с дросселем браузера?
Один из способов, который я могу придумать, заключается в асинхронной обработке логики «обновления таблицы»; то есть, когда Ajax-метод для перезагрузки XML-данных будет завершен, поместите данные в какой-то массив, а затем установите для запуска функцию (используя setInterval()
), которая будет обрабатывать один элемент массива за раз. Однако это немного похоже на воссоздание потоков в среде JavaScript, которое кажется очень сложным (например, что если другой запрос данных Ajax сработает, пока я все еще заново создаю DOM-узлы таблицы? И т. Д.)
обновление : Просто хотел объяснить, почему я принимаю ответ Роберга. Проводя некоторое тестирование, я обнаружил, что метод new Element()
в моей среде (я использую mootools ) примерно в 2 раза медленнее, чем традиционный document.createElement()
в IE7. Я запустил тест для создания 1000 <spans>
и добавления их к <div>
, использование new Element()
занимает около 1800 мс в IE7 (работает на виртуальном ПК), традиционный метод - около 800 мс.
Мой тест также показал еще более быстрый метод, по крайней мере, для простого теста, такого как мой: использование DocumentFragments, как описано Джоном Резигом . Выполнение того же теста на той же машине с IE7 заняло 247 мс, 9x улучшение по сравнению с моим первоначальным методом!