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

  • 相关阅读:
    url中特殊字符被转义成编码后处理
    使用axios解决$.ajax不能下载文件问题
    ES6学习-封装一个分页插件
    input输入框延时防抖
    ES6学习-封装tab选项卡
    JS的forEach()map()遍历和jQuery的$.each()$.map()遍历
    JavaScript正则表达式实现批量替换实际案例
    点击页面出现爱心效果
    vue父子组件传值
    Vue——实现简易计算器
  • 原文地址:https://www.cnblogs.com/xumengxuan/p/4473556.html
Copyright © 2011-2022 走看看