如何在密集的JavaScript处理期间(简要地)向浏览器提供控制权?

时间:2008-10-17 01:20:48

标签: javascript jquery

我已经阅读了关于在密集DOM处理(使用JavaScript)期间使用setTimeout()的帖子here,但是如何将此函数与下面的代码集成?以下代码适用于少量选项,但当选项数量太大时,我的“请等待”动画GIF会在本地JavaScript处理时冻结。谢谢!

function appendToSelect() {
    $("#mySelect").children().remove() ;
    $("#mySelect").html(
        '<option selected value="' + obj.data[0].value + '">'
        + obj.data[0].name
        + '</option>'
    );
    var j = 1 ;
    for (var i = 1; i < obj.data.length; i++) {
        $("#mySelect").append(
            '<option value="' + obj.data[i].value + '">'
            + obj.data[i].name
            + '</option>'
        ); 
    }
}

4 个答案:

答案 0 :(得分:29)

这是一个解决方案:

function appendToSelect() {
  $("#mySelect").children().remove();
  $("#mySelect").html(
    '<option selected value="'+obj.data[0].value+'">'
    + obj.data[0].name
    + '</option>'
  );
  obj.data.splice(0, 1); // we only want remaining data
  var appendOptions = function() {
    var dataChunk = obj.data.splice(0, 10); // configure this last number (the size of the 'chunk') to suit your needs
    for(var i = 0; i < dataChunk.length; i++) {
      $("#mySelect").append(
        '<option value="' + dataChunk[i].value + '">'
        + dataChunk[i].name
        + '</option>'
      );
    }
    if(obj.data.length > 0) {
      setTimeout(appendOptions, 100); // change time to suit needs
    }
  };
  appendOptions(); // kicks it off
}

不如@Borgar's解决方案那么优雅,但你明白了。基本上,我正在做同样的事情,但是在你的一个函数中,而不是像他那样将它分解为更高阶的函数。我喜欢他的解决方案,但如果你不喜欢,也许这对你有用。


编辑:对于那些没有立即看到它的人,这个解决方案和@Borgar's之间的主要区别之一是这个解决方案允许你设置在两者之间处理的数据的“块”的大小。每次超时。在处理完数组的每个成员之后,@Borgar's次超时。如果我有时间,我会尝试创建一个更高阶的函数来处理这个,所以它更优雅。虽然没有承诺! ;)


编辑:所以,这是我对@Borgar's解决方案的改编,它允许设置'块'大小并更容易配置超时值:

function incrementallyProcess(workerCallback, data, chunkSize, timeout, completionCallback) {
  var itemIndex = 0;
  (function() {
    var remainingDataLength = (data.length - itemIndex);
    var currentChunkSize = (remainingDataLength >= chunkSize) ? chunkSize : remainingDataLength;
    if(itemIndex < data.length) {
      while(currentChunkSize--) {
        workerCallback(data[itemIndex++]);
      }
      setTimeout(arguments.callee, timeout);
    } else if(completionCallback) {
      completionCallback();
    }
  })();
}

function appendToSelect() {
  $("#mySelect").children().remove();
  $("#mySelect").html(
    '<option selected value="' + obj.data[0].value + '">'
    + obj.data[0].name
    + '</option>'
  );
  obj.data.splice(0,1); // we only want remaining data      
  incrementallyProcess(function(data) {
    $("#mySelect").append(
    '<option value="' + data.value + '">'
    + data.name
    + '</option>'
   );
  }, obj.data, 10, 100, removeAnimatedGifFunction); // last function not required...
}

希望有所帮助 - 我认为这结合了两种解决方案的优点。 注意,第二个匿名函数不再使用索引值,而只是传入整个对象(带有value和name属性);这使得它更清洁,因为当前对象的索引实际上不是通常在迭代事物时很有用,IMO。

我确信仍然有一些事情可以做到更好,但这仍然是读者的练习。 ;)

答案 1 :(得分:20)

恰好我刚刚发布了这篇文章here。这是一个定时循环函数:

function processLoop( actionFunc, numTimes, doneFunc ) {
  var i = 0;
  var f = function () {
    if (i < numTimes) {
      actionFunc( i++ );  // closure on i
      setTimeout( f, 10 )
    } 
    else if (doneFunc) { 
      doneFunc();
    }
  };
  f();
}

根据您的情况,可以这样使用:

function appendToSelect () {

  $("#mySelect").children().remove() ;
  $("#mySelect").html(
      '<option selected value="' + obj.data[0].value + '">'
      + obj.data[0].name
      + '</option>'
  );
  var j = 1 ;

  processLoop(function (i){
    $("#mySelect").append(
        '<option value="' + obj.data[i].value + '">'
        + obj.data[i].name
        + '</option>'
    ); 
  }, obj.data.length);

}

您需要确保在迭代函数中有一个闭包或对obj变量的其他访问权限。

希望这有帮助。

答案 2 :(得分:4)

如果你需要更简单的东西,我写了一个jQuery插件来简化异步循环的编写:jQuery Async

使用该插件,您的代码可以重写为:

function appendToSelect() {
    $("#mySelect").children().remove() ;
    $("#mySelect").html(
        '<option selected value="' + obj.data[0].value + '">'
        + obj.data[0].name
        + '</option>'
    );

    /////////////////////////////
    var i = 1;
    $.whileAsync({
        test: function(){ i < obj.data.length; }
        loop: function()
        {
            $("#mySelect").append(
                '<option value="' + obj.data[i].value + '">'
                + obj.data[i].name
                + '</option>'
            ); 
            i++;
        }
    });
    /////////////////////////////
}

应该有助于响应。调整'批量'和'延迟'选项以获得更多控制权。

答案 3 :(得分:-1)

您需要重写该函数以缓存元素列表,然后使用某种计数器循环遍历列表。

然后当计数器达到计数器%max_num_before_wait == 0时,将超时调用回函数本身。

确保清除完整列表末尾的缓存和计数器,或使用带有额外计数参数的辅助功能。