Можно ли добавить большое количество DOM-узлов без удушья браузера? - PullRequest
1 голос
/ 09 января 2009

У меня есть веб-страница на моем сайте, которая отображает таблицу, перезагружает исходные данные 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 улучшение по сравнению с моим первоначальным методом!

Ответы [ 5 ]

6 голосов
/ 09 января 2009

100 <tr> на самом деле не так уж много ... вы все еще используете new Element() этого фреймворка? Это может быть причиной этого.

Вы должны проверить скорость new Element() против document.createElement() против .innerHTML

Также попробуйте построить dom-дерево "в памяти", а затем добавить его в конец документа.

Наконец, следите за тем, чтобы вы не смотрели на длину слишком часто, или на другие биты и тому подобное.

1 голос
/ 09 января 2009

Вы можете создать строковое представление и добавить его как innerHTML узла.

1 голос
/ 09 января 2009

Я столкнулся с подобными проблемами на круглых 3000 строк таблицы сложных данных, поэтому что-то не так с вашим кодом. Как это работает в Firefox? Можете ли вы проверить в нескольких разных браузерах.

Вы привязываетесь к onPropertyChange где-нибудь? Это действительно опасное, то есть событие, которое раньше вызывало у меня сильные, т.е. специфические головные боли. Используете ли вы где-нибудь CSS-селекторы? Это общеизвестно медленно на то есть.

0 голосов
/ 10 января 2009

Избегайте использования одного большого цикла for для рендеринга всех данных за один большой шаг. Вместо этого посмотрите на разбивку данных на более мелкие куски.

Визуализируйте каждый меньший фрагмент с помощью цикла while. После этого чанка вызовите следующий чанк с помощью setTimeout [time 1ms], чтобы дать браузеру «передышку».

Вы можете избежать одновременного использования цикла while и просто использовать setTimeout.

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

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

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

Здесь есть аккуратное изучение предупреждения: http://ajaxian.com/archives/what-causes-the-long-running-script-warning

0 голосов
/ 09 января 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...