倒计时

背景

记得之前在老东家曾经遇到的坑,前几天有朋友提起,记录一下。服务器

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 的时候从新向服务器请求计时时间游戏

相关文章
相关标签/搜索