代码之家  ›  专栏  ›  技术社区  ›  Jay Corbett

在密集的JavaScript处理过程中,如何(短暂地)将控制权交还给浏览器?

  •  22
  • Jay Corbett  · 技术社区  · 17 年前

    我读过这篇文章 here 关于在密集的DOM处理过程中使用setTimeout()(使用JavaScript),但是如何将此函数与下面的代码集成?下面的代码适用于少量选项,但当选项数量过大时,我的“请等待”动画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 回复  |  直到 17 年前
        1
  •  29
  •   Community Mohan Dere    9 年前

    以下是一个解决方案:

    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 解决方案,但你明白了。基本上,我在做同样的事情,但都是在你的一个函数中,而不是像他那样把它分解成一个高阶函数。我喜欢他的解决方案,但如果你不喜欢,也许这对你有用。


    @博加氏 @博加氏 之后超时 已处理数组的个数。如果我有时间,我会尝试创建一个高阶函数来处理这个问题,这样它会更优雅。但是没有承诺!;)


    编辑:这是我对 解决方案,允许更轻松地设置“块”大小和配置超时值:

    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。

    我相信还有一些事情可以做得更好,但这是留给读者的练习

        2
  •  20
  •   Community Mohan Dere    9 年前

    碰巧我刚才还在发这篇文章 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变量具有闭包或其他访问权限。

        3
  •  4
  •   Vincent Robert    16 年前

    如果您需要更简单的东西,我编写了一个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++;
            }
        });
        /////////////////////////////
    }
    

    应该有助于提高反应能力。调整“批量”和“延迟”选项以获得更多控制。

        4
  •  -1
  •   Geoff    17 年前

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

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