倒計時

背景

記得之前在老東家曾經遇到的坑,前幾天有朋友提起,記錄一下。服務器

setInterval

大多數人提及倒計時都會想起 setInterval ,包括之前的我。好比倒計時 60 秒oop

var time = 60;
var timer = setInterval(function(){
   if( --time > 0 ){
       console.log( time );
   }else{
       console.log( 'finish' );
       clearInterval(timer);
   }
},1000)

這種寫法咋一看沒問題,仔細看還沒看不出問題。。
時間一長就出bug了。
作個小實驗, 在 console 丟下代碼, 代碼只有 4 行,而後觀察 console 輸出this

var counter = 0;  // 做爲參照
setInterval(function(){
     console.log( ++counter % 60,new Date().getSeconds(), new Date().valueOf() );
},1000)

圖片描述

ok,代碼開始跑了。然而這個時候我開始看遊戲直播了,反正這玩意短期看不出結果的。偶爾回頭看看代碼運行的狀況spa

圖片描述

當看着 3 3 5 5 7 7 9 9 11 11 13 13 的時候。 我好慌code

另外的思路

var Timer = function(sec,callback){
   this.second = sec;                       // 倒計時時間(單位:秒)
   this.counter = 0;                        // 累加器,存儲跳動的次數
   this.timer = null;                       // setTimeout 實例
   this.before = (new Date()).valueOf();    // 開始時間 -- 時間戳,用於比較
   this.loop = function(){                  // 開始倒計時
       this.timer && clearTimeout(this.timer);
       var _this = this;
       this.counter++;
       var offset = this.counter * 1000 - (new Date()).valueOf() + this.before, // 倒計時每秒之間的誤差
           ctimestamp = this.second - this.counter;                             // 實際剩餘秒數
       this.timer = setTimeout(function(){
           if( ctimestamp < 1 ){
               typeof callback == 'function' && callback( ctimestamp, true );
               return;
           } else{ 
               typeof callback == 'function' && callback( ctimestamp, false );
               _this.loop();
           }
       },offset);
   }; 
   this.loop(); // 倒計時開始
   return this; 
};
// 調用
new Timer(2000,function(second,finish){
   console.log( finish ? 'finish' : second );
})

最後的話

這種寫法也有必定的隱患,好比用戶在倒計時開始以後修改本地的系統時間,就有可能出現較大的偏差。
我的以爲較好的解決方案就是在頁面 visibilitychange 的時候從新向服務器請求計時時間遊戲

相關文章
相關標籤/搜索