如何在javascript中打破长时间运行的功能,但保持性能

gor*_*dyr 6 javascript

我有一个长期运行的功能.它遍历一个大型数组并在每个循环中执行一个函数.

longFunction : function(){
       var self = this;
       var data = self.data;

       for(var i=0; len = data.length; i<len; i++){
              self.smallFunction(i);
       }
},
smallFunction : function(index){

// Do Stuff!

}
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,这很好,但是当我处理大约1500左右的数组时,我们得到了接收javascript执行警报消息的点.

所以我需要打破这个.我的第一次尝试是这样的:

longFunction : function(index){
       var self = this;
       var data = self.data;


      self.smallFunction(index);

      if(data.slides[index+1){
         setTimeout(function(){
            self.longFunction(index+1);
         },0);
      }
      else {
               //WORK FINISHED
      }

},
smallFunction : function(index){

// Do Stuff!

}
Run Code Online (Sandbox Code Playgroud)

所以在这里我将删除循环并引入一个自我调用函数,它会在每次迭代时增加其索引.要将控制权返回给主UI线程以防止javascript执行警告方法,我已经添加了一个setTimeout允许它在每次迭代后更新的时间.问题在于,通过这种方法,实际完成的工作需要花费10倍的时间.似乎正在发生的事情虽然setTimeout设置为0,但它实际上等待的时间更长,为10毫秒.哪个在大型阵列上很快就会建立起来.删除setTimeout和longFunction释放调用本身可以提供与原始循环方法相当的性能.

我需要另一个解决方案,一个具有与循环相当的性能但不会导致javascript执行警告的解决方案.不幸的是,webWorkers不能在这种情况下使用.

值得注意的是,在此过程中我不需要完全响应的UI.足以每隔几秒更新一次进度条.

将它分解成块的循环是一种选择吗?即,一次执行500次迭代,停止,超时,更新进度条,执行下一次500等等.

有更好的吗?

回答:

唯一的解决方案似乎是将工作分块.

通过将以下内容添加到我的自我调用函数中,我允许UI每250次迭代更新:

 longFunction : function(index){
           var self = this;
           var data = self.data;


          self.smallFunction(index);

          var nextindex = i+1;

          if(data.slides[nextindex){
            if(nextindex % 250 === 0){
             setTimeout(function(){               
                self.longFunction(nextindex);
             },0);
            }
            else {
                self.longFunction(nextindex);
            }
          }
          else {
                   //WORK FINISHED
          }

    },
    smallFunction : function(index){

    // Do Stuff!

    }
Run Code Online (Sandbox Code Playgroud)

我在这里所做的就是检查下一个索引是否可以除以250,如果是,那么我们使用超时来允许主UI线程更新.如果不是,我们会直接再次调用它.问题解决了!

Aln*_*tak 2

这是根据我之前编写的答案修改的一些批处理代码:

var n = 0,
    max = data.length;
    batch = 100;

(function nextBatch() {
    for (var i = 0; i < batch && n < max; ++i, ++n) {
        myFunc(n);
    }
    if (n < max) {
        setTimeout(nextBatch, 0);
    }
})();
Run Code Online (Sandbox Code Playgroud)