![](/img/trans.png)
[英]How can I update data in a for loop when my data is returned with a defer after the loop completes
[英]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() );
這里發生了什么?
我們基本上做的是:
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.