问题背景
近日我在开发一个答题小程序的时候,需要判断用户在规定答题时间内完成所有答题。但是,遇到了一个问题是使用setInterval(func,time)
的时候。担心会遇到一些问题。造成这个担心的原因是因为之前开发VUE单页应用的时候.从别的选项卡切换当前网页选项卡的时候.当前网页的倒计时会一度变得不如预期所想的那样(1s变一下数字)。而是倒计时的速度变得非常快。
于是,网上查到了如何使用setTimeOut()
来模拟setInterVal()
。
代码
var timer;
var i = 1;
timer = function () {
i++;
console.log(i);
if (i == 10) {
timer = function () {
console.log("终止运行");
}
}
setTimeout(timer, 500);
};
console.log(timer);
setTimeout(timer, 500);
刚开始理解这段代码的时候,我有点不知所以然.但是现在觉得是非常容易理解的.在这段函数是timer指向了一个内存空间的对象的引用(这个对象可以执行一些动作,它就是函数).
而setTimeout
会在倒计时结束之后去回调这个函数.而在回调这个函数到函数执行体内的时候,又会去设置一个定时器.这个定时器的回调函数指向了一个内存空间的引用.这还是Timer.所以它会起到模拟setInterval的效果.
同时,这种写法也是更为可控的.
如何取消这个定时器.只需要把timer设置为别的值,或者指向别的引用就可以了.
timer = function () {
console.log("终止运行");
}
以下是一种函数的写法
let timer = null
interval(func, wait){
let interv = function(){
func.call(null);
timer=setTimeout(interv, wait);
};
timer= setTimeout(interv, wait);
},
interval(function() {}, 20);
在VUE里,只需要将timer改为类似于this.timer
就可以了.
需要注意的是定时器并不是严格按照预期时间去执行的.它可能提前或者延迟执行.这和Javascript的语言特性有关.众所周知JavaScript是单线程语言.JavaScript的多线程和异步是依靠于EventLoop
(事件循环)机制来进行实现的.语言特性决定了定时器总是趋近于设定时间去执行的.
setTimeout(function () {
console.log("等等我呀");
console.timeEnd('caltime');
}, 1000);
console.log('我先执行咯');
console.time('caltime');
// 以下代码仅用于消耗调用栈的执行时间
var speedTime = [];
for (var i = 0; i < 100000000; i++) {
speedTime.push(i);
}
以上代码经过实际测试会发现,定时器的调用间隔不是1s.我这里经过测试是2s左右.这个与电脑硬件有关系.所以使用定时器来达到一些精准的任务并不是一个最好的选择.