這個問題有一個簡單的解決方法。由於setTimeout
的最小延遲時間是從定時器設置開始計算的,因此在處理每個塊之前,請務必在15 ms內設置定時器至少10 ms。當設置了幾個setTimeout
時,它們排隊並在下一個之後立即被調用,而沒有額外的延遲。這可以通過僅2個活動定時器來完成:
function runLongTask() {
var complete = false;
function processChunk() {
if(!complete) {
/* ... process chunk, set complete flag after last chunk ... */
//set new timer
setTimeout(processChunk);
} else {
/* ... code to run on completion ... */
}
}
//set a timer to start processing
setTimeout(processChunk);
//set an extra timer to make sure
//there are always 2 active timers,
//this removes the extra delay provided
//that processing each chunk takes longer
//than the forced delay
setTimeout(processChunk);
}
下面是比較變通的辦法,以每塊被處理後,設置新setTimeout
的傳統方法一個工作演示。在解決方法中,總是會有一個額外的setTimeout
,如果每個塊需要至少4 ms來減少每個塊大約4 ms或更長的處理時間(10塊大約40 ms或更多,如下所示)處理。請注意,該解決方法演示了僅使用2個活動計時器的情況。
function runForAtLeast15ms() {
var d = (+new Date) + 15;
while(+new Date < d);
}
function testTimeout(repetitions, next, workaround) {
var startTime = +new Date;
function runner() {
if(repetitions > 0) {
//process chunk
runForAtLeast15ms();
//set new timer
setTimeout(runner);
} else if(repetitions === 0) {
//report result to console
console.log((workaround? 'Workaround' : 'Traditional') +
' approach: ' +
((+new Date) - startTime) + ' ms');
//invoke next() function if provided
next && next();
}
repetitions--;
}
setTimeout(runner);
if(workaround){
//make sure that there are always 2
//timers running by setting an extra timer
//at start
setTimeout(runner);
}
}
//First: repeat runForAtLeast15ms 10 times
//with repeated setTimeout
testTimeout(10, function(){
//Then: repeat runForAtLeast15ms 10 times
//using a repeated set of 2 setTimeout
testTimeout(10, false, true);
});
你在你問的問題,同時回答了你自己的問題。 – Erevald
@Everald,是的。 [它受到SO的鼓勵](https://stackoverflow.blog/2011/07/its-ok-to-ask-and-answer-your-own-questions/)。我最近一直在努力解決這個問題,並找到了我想要記錄和分享的解決方案。通過分享,有人甚至可以提供更好的解決方案。 –