鑒于秒殺倒計時都是以一秒為單位,所以下面的例子也都以1000毫秒為計算,當然各個瀏覽器的實現和附加代碼的編寫也會造成一定的時間誤差,這部分誤差也合并在setTimeout的實現里面計算誤差。
<div id="show" style="width:500px;"></div>
<script>
var w = 1000;
var second = 0;
function showtime(){
showtime.curr= +new Date();
setTimeout('showtime()',1000);
document.getElementById("show").innerHTML+=second +" "+(showtime.curr-(showtime.last||showtime.curr)-1000)+" <br/>";
showtime.last=showtime.curr;
second++;
}
showtime();
</script>
可以看到在各個不同的瀏覽器在不同的秒數中出現不同的誤差,當然這個跟我本機的瀏覽器和環境有關
下面再將這些誤差值進行疊加測試
<div>
<div id="show" style="width:500px;"></div>
</div>
<script>
var w = 1000;
var i = 0;
function showtime(){
showtime.curr= +new Date();
f = setTimeout('showtime()',1000);
w+=(showtime.curr-(showtime.last||showtime.curr)-1000);
document.getElementById("show").innerHTML+=i+" "+(showtime.curr-(showtime.last||showtime.curr)-1000) +" "+w+"
<br/>";
showtime.last=showtime.curr;
i++;
}
showtime();
</script>
IE和chrome相對較為穩定,不知道是不是我本機環境的原因,firefox出現了很多大偏差,可以選擇定時清空這個誤差值來處理,或是采用鏈式的setTimeOut()來處理。
<div id="show" style="width:300px;"></div>
<script>
var w = 1000;
var i = 0;
var f ;
var t ;
var k = 0;
function showtime(){
showtime.curr= +new Date();
f = setTimeout('showtime()',1000);
w+=(showtime.curr-(showtime.last||showtime.curr)-1000);
document.getElementById("show").innerHTML+=i+" "+w+" "+(showtime.curr-(showtime.last||showtime.curr)-1000) +" <br/>";
showtime.last=showtime.curr;
i++;
}
function round(){
if(k!=0){
clearTimeout(f);
showtime();
document.getElementById("show").innerHTML+=" clear<br/>";
w=0;
}
setTimeout('round()',10000);
k++;
}
showtime();
round();
</script>
其實為什么javascript的定時器會出現所謂的不可靠或偏差的情況,這是可以理解的,最主要的問題是它們并不是所謂的線程,其實
javascript是運行于單線程的環境中,而定時器只是計劃代碼在未來某個執行的時間,執行的時間點是不能被保證的,因為在頁面的生命周期中,不同時間可能存在其他代碼,或各個瀏覽器的內核控制住javascript進程。
settimeout幾個見解
1、setTimeOut != thread | 時間片的并發調用
2、javascript以單線程的方式運行于瀏覽器的javascript引擎中
3、setTimeout 只是把要執行的代碼在設定的時間點插入js引擎維護的代碼隊列
4、setTimeout 插入代碼隊列并不意味著代碼就會立馬執行的
function showtime(){
// code 1...
f = setTimeout('showtime()',200); //200毫秒后要插入執行代碼對瀏覽器的js隊列
// code 2...
}
以上面面的代碼為例,說說它的執行流程
Code 1 -> 200毫秒后通知瀏覽器有隊列插入 -> Code 2 -> showtime() -> …
這個種重復遞歸可能會造成2個問題:
1 . 時間間隔可能小于定時調用的代碼的執行時間
2 . 時間間隔或許會跳過
時間間隔或許會跳過
5ms : code1 代碼執行完畢,200ms后有定時器進入隊列
205ms : 定時器進入隊列,code2繼續
300ms : function代碼結束,定時器從隊列中取出,執行
405ms : 第二個定時器進入隊列,第一個定時器的代碼在執行中
605ms : 第三個定時器意圖進入隊列失敗,這個點的settimeout丟失
為了避免這2個問題,可以采用鏈式setTimeOut()進行調用
setTimeOut(function(){
code處理...
setTimeOut(arguments.callee,interval);
},interval);
這個模式鏈式條用setTimeOut(),每次函數執行的時候都會創建一個新的定時器,第二個setTimeOut調用使用了arguments.callee來獲取當前執行的函數引用,并為其設置另外一個定時器,這樣的好處在于,在前一個定時器執行完之前不會向隊列中插入新的定時器代碼,確保不會有任何的確實間隔,而且它可以保證在下一次定時器代碼執行前,至少等待指定的間隔,避免連續的運行。
//-------------//
秒殺的定時器已經通過檢測正式運行了,博客記錄得不好,表達不是很清楚,關于setTimeOut的函數主要參考了《JavaScript高級程序設計(第2版)》的第18章。