我怎样才能推迟每个循环的jQuery

我在每个循环的jQuery中进行“重”canvas操作,导致较慢的设备(IE和iPad)有时变得完全没有响应。

所以我想我可以使用下划线的_.defer()来排列每个循环中的函数,如:

 function handleAsset = _.defer(function(){ //weightlifting goes here (partly async) }); $.each(assets, handleAsset); 

然而,这会抛出一个奇怪的错误(堆栈跟踪指向$.each ):

 Uncaught TypeError: Object 20877 has no method 'call' 

这种方法有缺陷吗? 这是由于处理程序函数内部的异步操作吗? 还有另一种/更好的方法来实现这一目标吗?

它有缺陷。 您应该尽可能在最低点解耦 / 分解代码。 我认为从长远来看,仅仅解耦循环的每次迭代是不够的。

但是,您真正需要做的是,设置异步失控计时器 ,为实现提供足够的空间来更新UI队列 (或UI线程 )。 这通常使用setTimeout() (client), nextTick (node.js)或setImmediate (即将推出)等方法完成。

例如,假设我们有一个数组,我们想要处理每个条目

 var data = new Array(10000).join( 'data-' ).split('-'); // create 10.000 entries function process( elem ) { // assume heavy operations elem.charAt(1) + elem.charAt(2); } for(var i = 0, len = data.length; i < len; i++ ) { process( data[i] ); } 

现在这段代码是一个经典循环,遍历数组并处理其数据。 它还会占用100%的CPU时间,因此只要处理所有条目就会阻塞浏览器UI队列 (这基本上意味着浏览器UI将冻结并变得无响应)。

为了避免这种情况,我们可以创建一个这样的结构:

 var data = new Array(10000).join( 'data-' ).split('-'); // create 10.000 entries function runAsync( data ) { var start = Date.now(); do { process( data.shift() ); } while( data.length && Date.now() - start > 100 ); if( data.length ) { setTimeout( runAsync.bind( null, data ), 100 ); } } runAsync( data.concat() ); 

这里发生了什么?

我们基本上做的是:

  • 获取arrays并在100ms的时间范围内处理尽可能多的数据/条目
  • 之后,停止处理(调用setTimeout )并为UI提供更新的机会
  • 只要我们仍然在数组中有数据,那就这样做

任何超过100毫秒的延迟通常被人眼识别为“ 滞后 ”。 下面的任何东西看起来都很流利而且很好(至少我们的眼睛会告诉我们)。 100ms是一个很好的值,作为最大处理时间的限制。 我甚至建议降到50ms。

需要注意的是, 整体处理时间会增加,但我认为更好的处理和更快的响应速度,而不是更快的处理和非常糟糕的用户体验。


快速演示:

  • 经典迭代(移动红色方块,将阻止)
  • 失控的脚本计时器(移动红色方块,将是可能的)

那么你想限制并发异步操作的数量? 您的实施中的缺陷是您将推迟每个操作,直到前一个操作完成。

一种选择是使用序列帮助程序,然后可以将此队列分解为更易于管理的块以进行处理。

https://github.com/michiel/asynchelper-js/blob/master/lib/sequencer.js

 var actions = []; $.each(assets, function(key, value) { actions.push(function(callback) { $.ajax({ url: 'process.php?id='+val, success: function(msg) { callback(); } }); }); } ); var sequencer = new Sequencer(actions); sequencer.start(); 

如果将actions数组拆分为两个数组,并让它们并排运行,则一次只能运行两个进程,直到两个队列都完成为止。

例如

 var arr1 = actions.splice(0,100); var arr2 = actions.splice(100,200); var sequencer1 = new Sequencer(arr1); sequencer1.start(); var sequencer2 = new Sequencer(arr2); sequencer2.start();