zoukankan      html  css  js  c++  java
  • javascript中的定时器

      本文地址:【http://www.xiabingbao.com/javascript/2015/04/20/javascript-timer/

      在以前的文章【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);
    View Code

       运行后,我们能够看到程序记录下的数据有(以下仅是部分数据):

    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,可以修改程序运行一下,是否能发现什么规律。

      博客地址:http://www.xiabingbao.com

  • 相关阅读:
    HDU4366 Successor 线段树+预处理
    POJ2823 Sliding Window 单调队列
    HDU寻找最大值 递推求连续区间
    UVA846 Steps 二分查找
    HDU3415 Max Sum of MaxKsubsequence 单调队列
    HDU时间挑战 树状数组
    UVA10168 Summation of Four Primes 哥德巴赫猜想
    UESTC我要长高 DP优化
    HDUChess 递推
    HDU4362 Dragon Ball DP+优化
  • 原文地址:https://www.cnblogs.com/xumengxuan/p/4473556.html
Copyright © 2011-2022 走看看