为什么尽量别用setInterval

 

在开发一个在线聊天工具时,经常会有过多少毫秒就重复执行一次某操作的需求。“没问题”,大家都说,“用setInterval好了。”我觉得这个点子很糟糕。

原因之一:setInterval无视代码错误

setInterval有个讨厌的习惯,即对自己调用的代码是否报错这件事漠不关心。换句话说,如果setInterval执行的代码由于某种原因出了错,它还会持续不断(不管不顾)地调用该代码。看代码

function a() {
    try{
        a.error.here;     } catch(e){
        $('body').append('<div>' + e.toString() + '</div>');
        throw e;
    } } function b() {
    try{
        b.error.here;     } catch(e)
    {
        $('body').append('<div>' + e.toString() + '</div>');
        throw e;
    }
    setTimeout(b, 2000);
} setInterval(a, 2000);
setTimeout(b, 2000);

原因之二:setInterval无视网络延迟

假设你每隔一段时间就通过Ajax轮询一次服务器,看看有没有新数据(注意:如果你真的这么做了,那恐怕你做错了;建议使用“补偿性轮询”(backoff polling)[1])。而由于某些原因(服务器过载、临时断网、流量剧增、用户带宽受限,等等),你的请求要花的时间远比你想象的要长。但setInterval不在乎。它仍然会按定时持续不断地触发请求,最终你的客户端网络队列会塞满Ajax调用。看代码

var n = 0,
    t = 0,
    u = 0,
    i, s = 'Stopping after 25 requests, to avoid killing jsfiddle’s server'; function a() {
    $.post('/ajax_html_echo/', function () {
        --n;
    });
    ++n;
    ++t;
    $('#reqs').html(n + ' a() requests in progress!');
    if (t > 25) {
        clearInterval(i);
        $('#reqs').html(s);
    }
} function b() {
    ++u;
    $.post('/ajax_html_echo/', function () {
        $('#req2').html('b(): ' + new Date().toString());
        if (u <= 25) {
            setTimeout(b, 500);
        } else {
            $('#req2').html(s);
        }
    });
} i = setInterval(a, 500);
setTimeout(b, 500);

原因之三:setInterval不保证执行

与setTimeout不同,你并不能保证到了时间间隔,代码就准能执行。如果你调用的函数需要花很长时间才能完成,那某些调用会被直接忽略。看代码

function slow() {
    $.ajax({
        url: '/echo/html/',
        async: false,
        data: {
            delay: 1
        },
        complete: function () {
        }
    });
    $('#reqs').text(~~((new Date() - start) / 100) + ' expected, ' + iters + ' actual');
    if (iters++ > 4) {
        $('#reqs').append('<br>Stopping after 5 iterations');
        clearInterval(iv);
    }
};
var iv = setInterval(slow, 100), start = +new Date(), iters = 0;

解决之道很简单:用setTimeout

 

与其使用setInterval,不如在适当的时刻通过setTimeout来调用函数自身。在前面两个示例中,使用setInterval的函数a都出错了,而使用setTimeout的函数b则表现很好。

如果必须保证间隔相等怎么办?

 

如果确实要保证事件“匀速”被触发,那可以用希望的延迟减去上次调用所花时间,然后将得到的差值作为延迟动态指定给setTimeout。 不过,要注意的是JavaScript的计时器并不是非常精确[2]。因此你不可能得到绝对“平均”的延迟,即使使用setInterval也不行,原因很多(比如垃圾回收、JavaScript是单线程的,等等)。此外,当前浏览器也会将最小的超时时间固定在4ms到15ms之间。因此不要指望一点误差也没有。

文中链接

1.http://github.com/blog/467-smart-js-polling

2.http://ejohn.org/blog/accuracy-of-javascript-time/

为什么尽量别用 setInterval的更多相关文章

  1. setTimeout和setInterval定时器使用详解测试

    var len=4; while(len--){ var time=setTimeout(function(){ console.log(len); },0); console.log(time); ...

  2. js的setInterval和setTimeout的那些浅坑

    setInterval和setTimeout的区别简单提一下 setInterval() :按照指定的周期(以毫秒计)来调用函数或计算表达式.方法会不停地调用函数,直到 clearInterval() ...

  3. 50 tips of JavaScript

    50 tips of JavaScript,这些坑你都知道吗? 1.在局部作用域中,使用var操作符定义的变量将成为定义该变量的作用域中的局部变量,省略var的会创建全局变量:在全局作用域中,不管是否 ...

  4. Javascript 对象 - 日期对象

    日期对象 在JavaScript中提供了Data对象,用于处理和日期有关的内容.通过Data对象可以获取系统时间.设置时间等.Data对象也具有prototype和constructor属性. 1创建 ...

  5. 50 tips of JavaScript,这些坑你都知道吗?

    1.在局部作用域中,使用var操作符定义的变量将成为定义该变量的作用域中的局部变量,省略var的会创建全局变量:在全局作用域中,不管是否使用var操作符定义的变量都会创建一个全局变量.但是,在全局作用 ...

  6. 你所不知道的setInterval

    在你所不知道的setTimeout记载了下setTimeout相关,此篇则整理了下setInterval:作为拥有广泛应用场景(定时器,轮播图,动画效果,自动滚动等等),而又充满各种不确定性的这set ...

  7. 前端开发:setTimeout与setInterval 定时器与异步循环数组

    前端开发:setTimeout与setInterval 定时器与异步循环数组 前言: 开通博客园三个月以来,随笔记录了工作中遇到的大大小小的难题,也看过无数篇令人启发的文章,我觉得这样的环境是极好的, ...

  8. 关于setInterval()你所不知道的地方

    前言:1.使用setInterval()的定时器会把事件运行的时间也包含在内,如果要精确算定时两个任务之间的时间,可以使用setTimeout()替换.2.当异步事件发生时,如mouse click, ...

  9. Node.js中setTimeout和setInterval的使用

    Node.js和js一样也有计时器,超时计时器.间隔计时器.及时计时器,它们以及process.nextTick(callback)函数来实现事件调度.今天先学下setTimeout和setInter ...

随机推荐

  1. Oracle 导入单表数据

    1. 测试一下 删除某一张表,然后 通过 expdp 数据库泵的备份来恢复数据. 测试过程 ) from bizlog COUNT() ---------- 151 drop table bizlog ...

  2. BroadcastReceiver介绍

    参考资料 : 基础总结篇之五:BroadcastReceiver应用详解 BroadcastReceiver用于接收广播信息,可以通过sendBroadcast等方法进行发送.sendBroadcas ...

  3. 微信小程序填坑之旅一(接入)

    一.小程序简介 小程序是什么? 首先“程序”这两个字我们不陌生.看看你手机上的各个软件,那就是程序.平时的程序是直接跑在我们原生的操作系统上面的.小程序是间接跑在原生系统上的.因为它嵌入在微信中,受微 ...

  4. 启动studio报错Gradle error

    在安装cuba studio后,启动时出现了以下错误: Gradle error The version of Gradle you are using does not support the Bu ...

  5. Kangax 的 ES7 兼容性表格

    Kangax 的 ES7 兼容性表格 https://kangax.github.io/compat-table/es2016plus/ Sort by             Engine type ...

  6. MT【93】二次函数衣服一件

    注:最后一行中$f(\dfrac{-x_1}{2})$应改为$f(\dfrac{-a}{2})$.有空再重新编辑.

  7. hadoop2相对hadoop1有非常重大的改进

    hadoop2相对hadoop1有非常重大的改进. 下面看一下在HDFS和MapReduce方面的改进: HDFS Federation(HDFS联邦)federation-background[1] ...

  8. 【暴力Treap 或 离线归并】子串计数(genies)

    子串计数(genies) Description 给出一段含有n个元素的序列a,要求求出子串和小于等于t的子串个数 Input Data 输入共两行第一行包含两个整数,n,t分别表示序列a元素的个数和 ...

  9. 前端学习 -- Css -- 盒子模式

    框模型: CSS处理网页时,它认为每个元素都包含在一个不可见的盒子里. 为什么要想象成盒子呢?因为如果把所有的元素都想象成盒子,那么我们对网页的布局就相当于是摆放盒子.我们只需要将相应的盒子摆放到网页 ...

  10. M公司的回忆录——L公司

    2013年3月笔者回国的第一站便是这人称有福之州的福州.受我兄弟之邀笔者来到了L公司.而这也是笔者与M公司相遇的前缘.此时的L公司只是一个刚起步的创业公司.与所有创业公司一样子——创业初期存在着很多问 ...