我怎样才能推迟每个循环的jQuery [英] How can I defer a jQuery each loop

查看:71
本文介绍了我怎样才能推迟每个循环的jQuery的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am doing "heavy" canvas operations in a jQuery each loop causing slower devices (IE and the iPad) to sometimes become totally unresponsive.

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

So I was thinking I could use underscore's _.defer() to queue the functions in my each loop like:

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

$.each(assets, handleAsset);

然而这引发了一个奇怪的错误(堆栈跟踪指向 $。每个):

Yet this throws a weird error (the stack trace points to the $.each):

Uncaught TypeError: Object 20877 has no method 'call'

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

Is this approach flawed? Is this due to async operations going on inside the handler function? Is there another / a better way to achieve this?

推荐答案

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

It is flawed. You should try to decouple / break up code at the lowest point possible. I think its unlikely that just decoupling each iteration of a loop is enough on the long run.

然而,你真正需要做的是,设置一个异步失控计时器,它为实现提供了足够的空间来更新 UI Queue (或 UI线程)。这通常使用 setTimeout()(客户端), nextTick (node.js)或<$ c等方法完成$ c> setImmediate (即将推出)。

However, what you really need to do is, to setup an asyncronous runaway timer which gives the implementation enough room to update the UI Queue (or UI thread). This typically is done using methods like setTimeout() (client), nextTick (node.js) or setImmediate (coming soon).

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

For instance, lets say we have an array, and we want to process each entry

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将冻结

Now this code is a classic loop, iterating over the array and process its data. It'll also consume 100% CPU time and will therefore block the browsers UI queue as long as it takes to process all entries (which basically means, the browser UI will freeze and become unresponsive).

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

To avoid that, we could create a construct like this:

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() );

这里会发生什么?

我们基本上做的是:


  • 在一个时间范围内获取数组并处理尽可能多的数据/条目 100ms

  • 之后,停止处理(调用 setTimeout )并让UI有机会更新

  • 只要我们仍然有数组中的数据

  • Take the array and process as much data/entries as possible within a timeframe of 100ms
  • After that, stop processing (call setTimeout) and give the UI a chance to update
  • do that as long as we still have data in the array

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

Any delay above 100 ms is typically recognized by the human eyes as "lag". Anything below that seems fluently and nice (at least our eyes will tell us so). 100ms is a good value as limit for maximum processing times. I'd even suggest to go down to 50ms.

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

The caveat here is that the overall processing time will increase, but I think its a better deal to have longer processing and stay responsive, instead faster processing and a very bad user experience.

快速演示:

  • classic iteration (move the red square around, will block)
  • runaway script timer (move the red square around, will be possible)

这篇关于我怎样才能推迟每个循环的jQuery的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆