为什么尽量别用 setInterval

摘自公众号前端大全---仅做个人学习之用!

英文: Colin Snover  译文:众成翻译/为之漫笔

www.zcfy.cc/article/why-i-consider-setinterval-to-be-harmful-zetafleet


为什么尽量别用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/',
        asyncfalse,
        data: {
            delay: 1
        },
        completefunction () {
        }
    });
    $('#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/

`LocationRequest.setInterval(100)` 是 Android 中用于设置 **位置更新最小时间间隔** 的方法,参数 `100` 表示 **100毫秒(即 0.1秒)**,即尝试每 0.1 秒获取一次位置更新,理论回调频率为 **10Hz**。 ### **关键点解析** | **参数** | **说明** | |----------------|-------------------------------------------------------------------------| | **100(单位:毫秒)** | 系统会**尽量**按照此间隔触发回调,但实际频率受硬件、系统策略和功耗限制影响。 | | **实际表现** | 可能无法稳定达到 10Hz(尤其在低功耗模式或弱信号环境下)。 | | **功耗影响** | 高频请求(如 10Hz)会显著增加电量消耗,可能触发 Android 的节流机制。 | --- ### **与其他参数的关联** ```java LocationRequest request = new LocationRequest.Builder(100) // 最小间隔100ms(10Hz) .setMinUpdateDistance(0) // 无视位移变化,强制按时间间隔更新 .setPriority(PRIORITY_HIGH_ACCURACY) // 高精度模式(GPS优先) .build(); ``` - **`setMinUpdateDistance(0)`**:取消位移变化限制,确保严格按时间间隔回调。 - **`PRIORITY_HIGH_ACCURACY`**:使用 GPS 而非网络定位,提高精度但进一步增加耗电。 --- ### **注意事项** 1. **系统限制**: - Android 可能自动降低频率(如进入省电模式时回调可能降至 1Hz)。 - 部分厂商 ROM 会忽略过低间隔(如强制最低 1秒)。 2. **替代方案**: - 需要极高频率时,可结合 GNSS 原始数据(`GnssMeasurement`)自行解算,但复杂度高。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值