Обновление DOM, сопровождаемое большим циклом, не отображается вовремя - PullRequest
4 голосов
/ 29 февраля 2012

Часть моей страницы содержит ~ 9000 элементов, и ее приходится часто перестраивать, что может занять несколько секунд.

Итак, я создал небольшой виджет наложения, который покрывает элемент Loading...сообщение.Прямо перед тем, как перестроить элемент, я вызываю showOverlay(), а после цикла я вызываю hideOverlay().

Но цикл блокирует страницу до отображения моего сообщения Loading..., поэтому оно никогда не появляется.

function rebuild() {
  showOverlay();    // The overlay never appears...
  for (var i=0;i<9000;i++) {
    // append element...
  }
  hideOverlay();
}

Как я могу ждать, пока оверлей будет отрисован ПЕРЕД тем, как я начну цикл?

Ответы [ 4 ]

4 голосов
/ 29 февраля 2012
function do_rebuild() {
  for (var i=0;i<9000;i++) {
    // append element...
  }
  hideOverlay();
}


function rebuild() {
  showOverlay();    // The overlay will appear
  window.setTimeout('do_rebuild();',1);
}

Это единственный кросс-браузерный способ, который я знаю.

1 голос
/ 29 февраля 2012

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

var counter = 0;
function rebuild() {
    showOverlay();
    doWork();
}
function doWork() {
    if(counter < 9000){
        // append element
        counter++;
        setTimeout(function(){
            doWork();
        },10);
    }
    else {
        hideOverlay();
    }
}

РЕДАКТИРОВАТЬ : хотя этот ответ на обработку страницы будет занимать значительно больше времени.Где-то в области 90 секунд, что довольно неприемлемо, другой альтернативой может быть установка таймаута каждые 100 итераций, что добавит около 1 секунды к общему времени загрузки, но должно остановить замораживание страницы.

function doWork() {
    if(counter < 9000){
        // append element
        if(counter % 100 == 0) {
            setTimeout(function(){
                doWork();
            },10);
            counter++;
        }
        else {
            doWork();
            counter++;
        }
    }
    else {
        hideOverlay();
    }
}
0 голосов
/ 29 февраля 2012

вы можете попробовать это:

var loopCount = 0,
    build = function() {

    var frgm = document.createDocumentFragment();
    for (var i = 0; i < 200 && loopCount < 9000; i++) {
        // some codes
        frgm.appendChild(someElement);
        loopCount ++;
    }
    parentNode.appendChild(frgm);

    if (loopCount < 9000) {
         setTimeout(build, 10);
    }
};

function rebuild() {
  showOverlay();    // The overlay never appears...
  build();
  hideOverlay();
}
0 голосов
/ 29 февраля 2012

Другие ответы показывают, как это сделать «псевдопоточными» способами, используя таймеры.

Тем временем я узнал о Web Workers , которые представляют собой потоковое решение, которое отделяет выполнение скрипта от обновлений DOM.

В настоящее время они поддерживаются в WebKit и Firefox, и поддержка планируется для IE 10.

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