DOM更新后跟一个大循环不会及时呈现

时间:2012-02-28 22:26:58

标签: javascript html loops

我的页面中有大约9000个元素,必须经常重建,这可能需要几秒钟。

所以,我制作了一个覆盖元素的小窗口小部件Loading..。信息。在我重建元素之前,我调用showOverlay(),然后在循环之后调用hideOverlay()

但是在显示Loading...消息之前,循环会锁定页面,因此它永远不会出现。

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

如何在开始循环之前等待渲染叠加?

4 个答案:

答案 0 :(得分:4)

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 :(得分:1)

您需要将循环置于设置超时内,以便它不会占用页面。即使您的叠加显示,也没有人喜欢他们的页面冻结

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();
    }
}

答案 2 :(得分:0)

其他答案显示了如何使用计时器以“伪线程”方式执行此操作。

与此同时,我了解了Web Workers,这是一个将脚本执行与DOM更新分开的线程解决方案。

WebKit和Firefox目前支持它们,并计划为IE 10提供支持。

答案 3 :(得分:0)

你可以试试这个:

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();
}