浏览器定时器问题

浏览器定时器问题最近在做一个h5小游戏,游戏里有这样一个场景,两个倒计时同时在一分钟的时候开始倒计时,两者几乎是同时开始的,理论上,我希望的结果是他们能够几乎同

大家好,欢迎来到IT知识分享网。

最近在做一个h5小游戏,游戏里有这样一个场景,两个倒计时同时在一分钟的时候开始倒计时,两者几乎是同时开始的,理论上,我希望的结果是他们能够几乎同时倒计时到0,但是,实际发现,在一段时间内,他们产生了很大的误差(大于一秒),于是,真正认识到js的定时器是那么的不靠谱了。为啥不靠谱。本篇文章来理理总结下。

浏览器中的主要的定时器有两种,世人皆知:setTimeout和setInterval,这两个方法让程序在浏览器中的延时执行,为什么说是浏览器中而不是js中,因为定时器方法是浏览器宿主提供的,而非js本身自带,脱离了浏览器也许就不管用了。

使用实例

1 var timerId=setTimeout(function{ 2 alert("我要延时两秒来执行"); 3 },2000);
1 var timerId1= setInterval(function{ 2 alert("我一秒钟执行一次"); 3 },1000);

如果一切正常,第一段代码将在两秒后弹出弹窗,第二段代码将没一秒钟弹出一次弹窗。一切总是那么的顺畅。我们仿佛看到一个掐着秒表的调度员在调度和控制这些。

再看一段代码

1 setTimeout(function{ 2 alert(1); 3 },1000); 4 alert(2);

执行这段代码,我们发现先弹出了2,再弹出了1;也就是说我们发现定时器的一个特性,那就是“异步执行”!

当然js是单线程的,为何能产生了异步的特性。回想下,在我们的js代码里,还有谁是异步呢,很自然,我们想到了ajax的异步。还有鼠标点击事件的异步,

这是为什么呢?难道还有其他线程在操控着这些异步。答案是肯定的。

回顾下几个知识点:

1.浏览器5个常驻线程

js引擎分配的线程

GUI渲染页面的线程

浏览器事件线程

浏览器定时器触发线程

浏览器http请求线程

那么就很好理解了,js引擎的线程按照他的单线程按部就班的执行着代码。GUI负责渲染页面,但是他和js引擎的线程是互斥的,也就是只允许同时又一个线程在执行。浏览器事件线程负责处理浏览器点击等事件,浏览器定时器线程负责处理定时器的任务安排,http请求线程负责处理网络请求。

一切看上去很井然有序,那既然有专门的线程去安排这些事情,为何文章开篇会产生定时误差呢,

原来浏览器的多线程其实只是处理事件的触发,至于事件的回调的执行,还是交给js的引擎线程来执行的,因为js引擎是单线程的,所以在js引擎中维护着一个队列,当这些事件触发的时候,就会把回调插入到这个位于正常js代码的队列中,队列是在正常代码块的末尾位置。正因为最终他们的回调还是单线程执行的,所以一旦上一步操作中有比较耗时间的操作,定时操作就会向后产生延误。那么就会出现上面开题所说的情况,而且这种延误会产生叠加。看下下面这张图,再理解下,为何上面的代码块先执行了alert(2)然后再执行了alert(1);

浏览器定时器问题

图片来源(http://hao.jser.com/archive/8414/)

这下似乎问题都出来了,在我的小游戏当中,维持着很多缓动定时器还有一些轮询的ajax,所以可以理解有很多耗时的任务,他们阻碍了定时器的按部就班。

那如何修复这种情况呢,毕竟问题还是要解决的。

两种解决方案

1.尽量使用setTimeout来替代setInterval,具体做法是:

1 function timer(fn,delay){ 2 var s=setTimeout(function{ 3 fn; 4 timer(fn,delay); 5 },delay) 6 } 

这种做法的原理是,每次执行setTimeout的时候都会重新触发定时器事件,重新插入队列事件,延误会再下次被清零,避免了连续的队列延迟产生叠加

2.即时校准

 1 var count=0; 2 var t1=(new date).getTime; 3 var delay=1000; 4 function timer(fn,delay){ 5 var s=setTimeout(function{ 6 count++; 7 fn; 8 var t2=(new date).getTime; 9 var newdelay = delayer - (t2-t1-count*delay); 10 timer(fn,newdelay); 11 }) 12 } 13 timer(function{ 14 console.log(111); 15 },delay);

这种方式比起第一种方式更加暴力,效果明显,保证了时间最终的基本一致,但是会有因为校准而产生的时间跳跃现象。

好,问题算是解决了。

定时器还会涉及一些问题

1.那就是定时器的作用域里 this指向的肯定是window 除非你强制改变。

2.定时器哪怕你delay设置为0,也是会被插入到最后的队列中执行的。

3.定时器执行后会返回一个定时的索引给你,你可以通过clearTimeout 和clearInterval来定点清除

就先总结到这里了!

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/58623.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信