[英]Javascript setTimeout with 0 delay issue
我注意到了一個奇怪的行為:如果我有一系列任務並希望推遲執行,那么我可以為每個任務使用setTimeout並設置0延遲。 (請參閱http://javascript.info/tutorial/events-and-timing-depth#the-settimeout-func-0-trick )
一切運行正常:將任務排入隊列並盡快執行。
但是...如果各種setTimeout的調用非常接近 ,那么我發現有時(很少發生!)執行順序不正確 。 為什么?
沒有人曾承諾過他們會以“正確”的順序被解雇(具有相同超時的任務將按照設置為超時的順序執行)。 setTimeout
僅保證:
沒有關於執行順序的消息。 實際上,即使實現者嘗試保留順序(甚至是副作用),也很可能沒有足夠的時間解析來為所有任務提供唯一的排序順序,並且二進制堆(很可能在這里使用)不保留等號的插入順序)。
如果要保留延遲任務的順序,則僅在上一個任務完成后才入隊。
這應該工作:
var defer = (function(){
//wrapped in IIFE to provide a scope for deferreds and wrap
var running = false;
var deferreds = [];
function wrap(func){
return function(){
func();
var next = deferreds.shift();
if(next){
setTimeout(wrap(next),0);
}else{
running = false;
}
}
}
return function(func){
if(running){
deferreds.push(func);
}else{
setTimeout(wrap(func),0);
running = true;
}
}
})()
演示: http : //jsfiddle.net/x2QuB/1/
您可以考慮使用jquery deferreds(或deferreds的其他實現),它可以非常優雅地處理此模式。
需要注意的重要一點是,延遲完成的回調將按添加的順序執行。
var createCountFn = function(val){
return function(){
alert(val)
};
}
// tasks
var f1 = createCountFn(1),
f2 = createCountFn('2nd'),
f3 = createCountFn(3);
var dfd = $.Deferred();
dfd.done(f1).done(f2).done(f3);
dfd.resolve();
HTML5規范草案指出setTimeout方法可以異步運行(這意味着可能不會保留執行回調的順序),這可能是瀏覽器正在執行的操作。
setTimeout()方法必須運行以下步驟:
...
6.返回句柄,然后繼續異步運行此算法。
7.如果方法上下文是Window對象,請等待直到與該方法上下文關聯的Document完全處於活動狀態達另一個超時毫秒(不必連續)。
在任何情況下,都可以通過執行以下操作來解決此問題:
function inOrderTimeout(/* func1[, func2, func3, ...funcN], timeout */)
{ var timer; // for timeout later
var args = arguments; // allow parent function arguments to be accessed by nested functions
var numToRun = args.length - 1; // number of functions passed
if (numToRun < 1) return; // damm, nothing to run
var currentFunc = 0; // index counter
var timeout = args[numToRun]; // timeout should be straight after the last function argument
(function caller(func, timeout) // name so that recursion is possible
{ if (currentFunc > numToRun - 1)
{ // last one, let's finish off
clearTimeout(timer);
return;
}
timer = setTimeout(function ()
{ func(); // calls the current function
++currentFunc; // sets the next function to be called
caller(args[currentFunc], timeout);
}, Math.floor(timeout));
}(args[currentFunc], timeout)); // pass in the timeout and the first function to run
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.