在以前的文章【javascript中的定时器】中,简单的介绍了一下setTimeout()和setInterval()两个定时器方法的使用和原理。不过在昨天给我的node即时聊天系统添加消息提示时,发现了定时器新的特性。当然,这对于我来说是新的发现,其实这些东西早就已经存在了。
1. 最小运行时间间隔
在setTimeout()和setInterval()我们能够设定时间间隔,来让下个事件大致
发生在哪个时间段。假如我们设置时间间隔是0的话,那是不是就会在0ms之后执行呢,也就是立即执行。我们可以采用下面的代码输出一下:
function get(){ var timer = null; var date = null; var diff = 0; var last = 0; var now = 0; var nums = 0; var color = '#000'; var process = document.getElementById("process"); timer = setInterval(function(){ date = new Date(); now = date.getTime(); diff = now-last; // 前后两个时间差 last = now; nums++; color = diff===0?'#f00':'#000'; process.innerHTML += '<p>'+now+' (<span style="color:'+color+'">'+diff+'</span>)</p>'; if(nums>=100){ clearInterval(timer); } }, 0); } get();
我们把每次执行setInterval()前后的时间差打印到屏幕中(以下数据使用chrome 42.0.2311.90版本测试):
1429545782409 (1) 1429545782412 (3) 1429545782414 (2) 1429545782420 (6) 1429545782425 (5) 1429545782430 (5) 1429545782437 (7) 1429545782443 (6) 1429545782449 (6) 1429545782454 (5) 1429545782460 (6) 1429545782466 (6) 1429545782471 (5) 1429545782476 (5) ...
从打印出的数据可以看出,setInterval()的时间间隔为0ms时,输出的时间差基本都在1~10ms之间,也是能在可以接受的范围内。IE11下的测试与chrome的数据基本一致,而在firefox下能够出现0
的时间差。
2. 标签不可见时的定时器间隔
其实不管是把时间间隔设定为0ms还是其他的时间间隔,运行时都会有时间误差的,比设定的间隔多1~16ms毫秒左右,有的时候还会相差更多。
我们有时会在某个场合对标题进行闪动,提示给用户当前标签页有新消息产生:
var backup = document.title; // 存储原标题 function blink(){ document.title = document.title == backup? "【有新消息】" : backup; } blink(); timer = setInterval(blink, 500);
上面的代码能够进行500ms的标题轮流闪动,当我们处在当前标签页时,基本感觉不出定时器产生的误差。可是如果我们切换到其他的标签页或者最小化时,我们就能够看到,标题的闪动变慢了很多,差不多提升到1000ms左右了。
为了更加准确的记录时间间隔的变化,我们特此将上面的代码进行如下的补充,标题进行闪动时记录当前的毫秒时间戳,同时标记出当前标签页可见时的状态和不可见时的状态【查看演示】:
1 // 标题闪动 2 function blinkTile(title, timeout){ 3 var self = this; 4 var timer = null; 5 var backup = document.title; 6 var last = 0; 7 var process = document.getElementById("process"); 8 9 self.init = function(title, timeou){ 10 if(title != undefined){ 11 self.title = title; 12 } 13 self.timeout = timeout == undefined? 500: timeout; 14 } 15 16 self.start = function(){ 17 self.stop(); 18 19 function blink(){ 20 document.title = document.title == backup? self.title : backup; 21 self.check(); 22 } 23 blink(); 24 timer = setInterval(blink, self.timeout); 25 } 26 27 28 29 self.stop = function(){ 30 if(timer != null){ 31 document.title = backup; 32 clearInterval(timer); 33 timer = null; 34 } 35 } 36 37 38 // 打印时间差,同时让滚动条在最下边 39 self.check = function(){ 40 var date = new Date(); 41 var now = date.getTime(); 42 var diff = now-last; 43 last = now; 44 process.innerHTML += '<p>'+now+' ('+diff+')</p>'; 45 process.scrollTop = process.scrollHeight; 46 } 47 48 self.init(title, timeout); 49 } 50 var blink = new blinkTile('【新消息】', 500); 51 blink.start(); 52 53 // 标签页的可见状态 54 var hidden, state, visibilityChange; 55 if (typeof document.hidden !== "undefined") { 56 hidden = "hidden"; 57 visibilityChange = "visibilitychange"; 58 state = "visibilityState"; 59 } else if (typeof document.mozHidden !== "undefined") { 60 hidden = "mozHidden"; 61 visibilityChange = "mozvisibilitychange"; 62 state = "mozVisibilityState"; 63 } else if (typeof document.msHidden !== "undefined") { 64 hidden = "msHidden"; 65 visibilityChange = "msvisibilitychange"; 66 state = "msVisibilityState"; 67 } else if (typeof document.webkitHidden !== "undefined") { 68 hidden = "webkitHidden"; 69 visibilityChange = "webkitvisibilitychange"; 70 state = "webkitVisibilityState"; 71 } 72 73 var process = document.getElementById("process"); 74 // 添加监听器,在title里显示状态变化 75 document.addEventListener(visibilityChange, function() { 76 if(document[state]=="hidden"){ 77 process.innerHTML += '<p style="color:#f00;">====== 离开 ======</p>'; 78 }else{ 79 process.innerHTML += '<p style="color:#f00;">++++++ 回来 ++++++</p>'; 80 } 81 }, false);
运行后,我们能够看到程序记录下的数据有(以下仅是部分数据):
1429547223336 (505) 1429547223837 (501) ====== 离开 ====== 1429547225296 (1459) 1429547226296 (1000) 1429547227296 (1000) 1429547228297 (1001) ++++++ 回来 ++++++ 1429547229137 (840) 1429547229637 (500)
我们很清楚的看到,当标签页不可见时(“离开”后),时间差上升了1000ms左右;标签页可见时(“回来”后),时间差又恢复到了500ms左右。不过在标签页刚切换完的时候,时间差的变化比较大,后来就趋于稳定了。其实浏览器为了在标签页不可见时减少CPU的利用率和电池等的消耗,特地将时间间隔进行提高。
不过这里要指出的是,在IE11下,标签的可见状态不会影响定时器的时间间隔。
3. 总结
上面的代码中,我们设定的时间间隔是500ms,标签页不可见时,时间间隔就会提升到1000ms;如果我们把时间间隔设定到1500ms呢,2500ms,可以修改程序运行一下,是否能发现什么规律。