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

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

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

这是一个解决方案:

 function appendToSelect() { $("#mySelect").children().remove(); $("#mySelect").html( '' ); 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( '' ); } if(obj.data.length > 0) { setTimeout(appendOptions, 100); // change time to suit needs } }; appendOptions(); // kicks it off } 

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


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


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

 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( '' ); obj.data.splice(0,1); // we only want remaining data incrementallyProcess(function(data) { $("#mySelect").append( '' ); }, obj.data, 10, 100, removeAnimatedGifFunction); // last function not required... } 

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

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

碰巧我刚才在这里张贴这个。 这是一个定时循环函数:

 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( '' ); var j = 1 ; processLoop(function (i){ $("#mySelect").append( '' ); }, obj.data.length); } 

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

希望这可以帮助。

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

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

 function appendToSelect() { $("#mySelect").children().remove() ; $("#mySelect").html( '' ); ///////////////////////////// var i = 1; $.whileAsync({ test: function(){ i < obj.data.length; } loop: function() { $("#mySelect").append( '' ); i++; } }); ///////////////////////////// } 

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

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

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

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