Есть ли событие IE Render Complete? - PullRequest
8 голосов
/ 04 августа 2011

При попытке определить, почему загрузка страницы занимает 20 секунд, я обнаружил странное поведение в IE8.

Сценарий такой.

Я выполняю вызов ajax, он возвращает иобратный вызов выглядел примерно так

$("#StoreDetailsContainer").html($(tableHtml));
var StoreDetailsTable = $("#StoreDetailsTable");
StoreDetailsTable.tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" });
StoreDetailsTable.filtertable({ cssChildRow: "SubTable" });

Однако для завершения этого бита кода потребовалось 20 секунд.

Я возился, определял время и выдает предупреждения между методами, и внезапно,это заняло всего 6 секунд.Я немного поэкспериментировал и обнаружил, что если я введу задержку после вызова .html() и до того, как я попытаюсь манипулировать DOM, страница отобразится НАМНОГО быстрее.Теперь это выглядит так:

$("#StoreDetailsContainer").html($(tableHtml));
window.setTimeout(function() {
    var StoreDetailsTable = $("#StoreDetailsTable");
    StoreDetailsTable.tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" });
    StoreDetailsTable.filtertable({ cssChildRow: "SubTable" });
}, 100);

Это также занимает всего 6 секунд, несмотря на добавление к процессу дополнительных 1/10-й секунды.

Моя теория такова, потому что DOM не былIE полностью выводится на экран с помощью вызова .html(), прежде чем пытаться работать с ним, происходит какая-то блокировка.

Есть ли способ определить, когда IE завершил рендеринг того, что было добавлено вDOM .html(), поэтому мне не нужно использовать произвольное значение при вызове setTimeout?

Ответы [ 5 ]

6 голосов
/ 09 августа 2011

Вы почти на месте со своим анализом. Позвольте мне попытаться объяснить, почему setTimeout имеет значение.

Если вы посмотрите на эту замечательную статью о рендеринге DOM, вы поймете, что .html() вызовет reflow .

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

Решение - нам нужно сообщить браузеру, что наши html изменения сделаны, и вы можете завершить процесс рендеринга. Способ сделать это - 1) завершить ваш скрипт 2) использовать setTimeout, чтобы передать выполнение браузеру.

Выполнение setTimeout с задержкой 0 мс также работает, потому что setTimeout в основном отказывается от контроля над блоком сценария. Одна из причин, по которой сценарии, связанные с анимацией, так сильно зависят от setTimeout и setInterval.

Другим потенциальным улучшением было бы использование documentFragments, кратко объясненное Джоном Резигом здесь

Я думаю, что объединение этих двух должно дать больше скорости, но, конечно, нет способа узнать, пока не будет выполнено профилирование!

3 голосов
/ 08 августа 2011

Вы можете добавить изображение в один пиксель к ответу обратного вызова, получить это изображение из DOM после .html (..) и присоединить его к событию onload.Я не могу себе представить, что событие onload изображения может сработать, пока браузер не отобразит его.

Убедитесь, что изображение имеет уникальный идентификатор в src, чтобы оно не кэшировалось ...

Странная проблема, с которой вы столкнулись - я уверен, что кто-то предложит более изящное решение:)

B

2 голосов
/ 08 августа 2011

Вызов setTimeout задерживает данную функцию как минимум на указанное время, но она никогда не запускается до завершения текущего выполнения скрипта.Тем не менее, вы можете заменить свое время ожидания на 0 секунд.

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

Третье предположение, которое может помочь, заключается в том, что вы гарантируете анализHTML-код вне макета страницы.Это предотвратило бы рисование наполовину готовых макетов снова и снова.Для этого вы можете отсоединить элемент StoreDetailsContainer от DOM до вашего звонка на html.Теперь в IE есть изменение для создания DOM без влияния на макет.После этого вы снова добавите StoreDetailsContainer в DOM.По сравнению с обычным набором innerHTML это отсоединение и повторное присоединение контейнера позволяет вам контролировать, когда анализируется HTML для построения дерева DOM и когда вычисляется макет.

0 голосов
/ 03 января 2016

Я думаю, что это может работать так:

$("#StoreDetailsContainer").html($(tableHtml))
.find("#StoreDetailsTable")
.tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" })
.filtertable({ cssChildRow: "SubTable" });
0 голосов
/ 12 августа 2011

Попробуйте этот код.Событие load запускается после события ready, поэтому оно может работать.

$(document).ready(function(){
  $("#StoreDetailsContainer").html($(tableHtml))
  });
$(window).load(function(){
  $("#StoreDetailsTable").tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" }).filtertable({ cssChildRow: "SubTable" });
  });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...