簡體   English   中英

我怎樣才能推遲每個循環的jQuery

[英]How can I defer a jQuery each loop

我在每個循環的jQuery中進行“重”畫布操作,導致較慢的設備(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() );

這里發生了什么?

我們基本上做的是:

  • 獲取陣列並在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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM