讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議121:使用定時器限時運行代碼 >

建議121:使用定時器限時運行代碼

有時每次只執行一個任務,這樣效率不高。考慮這樣一種情況:處理一個擁有1000項的數組,每處理一項需要1 ms。如果在每個定時器中處理一項,在兩次處理之間間隔25 ms,那麼處理此數組的總時間是(25+1)×1000=26 000 ms,也就是26 s。如果每批處理50個,每批之間間隔25 ms,那麼結果會怎麼樣呢?

整個處理過程變成(1000/50)×25+1000=1500 ms,也就是1.5 s,而且用戶也不會察覺界面阻塞,因為最長的腳本運行只持續了50 ms。通常批量處理比每次處理一項速度更快。

如果記住JavaScript可連續運行的最大時間是100 ms,那麼可以優化先前的模式。建議將這個數字削減一半,不要讓任何JavaScript代碼持續運行超過50 ms,這只是為了確保代碼永遠不會影響用戶體驗。可通過原生的Date對像跟蹤代碼的運行時間,這是大多數JavaScript分析工具所採用的工作方式,例如:


var start=+new Date,stop;

someLongProcess;

stop=+new Date;

if(stop-start<50){

alert("Just about right.");

}else{

alert("Taking too long.");

}


由於每個新創建的Data對象都以當前系統時間初始化,因此可以週期性地創建新Data對象並比較它們的值,以獲取代碼運行時間。通過加號(+)將Data對像轉換為一個數字,這樣在後續的數學運算中就不必再轉換了。這一技術也可用於優化以前的定時器模板。timedProcessArray方法通過一個時間檢測機制可在每個定時器中執行多次處理,例如:


function timedProcessArray(items,process,callback){

var todo=items.concat;

setTimeout(function{

var start=+new Date;

do{

process(todo.shift);

}while(todo.length>0&&(+new Date-start<50));

if(todo.length>0){

setTimeout(arguments.callee,25);

}else{

callback(items);

}

},25);

}


此函數中添加了一個do-while循環,它在處理完每個數組項後檢測時間。在定時器函數運行時,因為數組中存放了至少一個項,所以後對循環進行測試比先測試更合理。在Firefox 3中,如果process是一個空函數,處理一個1000項的數組需要34~38 ms,那麼原始的timedProcessArray函數處理同一個數組需要超過25 000 ms。這就是定時任務的作用,避免將任務分解成過於瑣碎的片斷。