海滨擎蟹

js 使用 setInterval 出现函数执行次数指数级递增的问题

问题代码如下:

    function getSumData() {
        $.post('xxx?action=getSumData',{},function (res) {
            if (res.errorCode) {
                console.log(res.errorMes);
                return false;
            }
        });
        setInterval(function () {
            getSumData()
        }, 60000);
    }
    $(function () {
        getSumData();
    });

一开始以为是 ajax 请求,但 ajax 属于异步调用,不会影响定时器,更不会让调用次数激增。

主要犯错的原因还是在 setInterval 函数理解上。setInterval 是间歇性调用,在这里就是每 60 秒调用一次,每次调用完不会自动停止。setInterval 写在函数内部意味着,每调用一次函数这种间歇调用就会增加一倍,最后导致的结果就是浏览器卡顿,电脑 CPU 几乎跑满,然后所有的鼠标、键盘等输入操作会延迟到很夸张的程度。

解决方法:将 setInterval 替换成 setTimeout 就好了。

之前自己还总结过一次:Jquery 中使用定时器 setInterval 和setTimeout,可惜犯错时总是想不起来。

然后又想到前同事(搞前端的)去盖亚工厂面试遇到的一道面试题:

for (var i = 0; i <10; i++) {
    setTimeout(function () {
        console.log(i);
    }, 0);
}

结果输出是 10 个 10,而非我想象中的 0-9。setTimeout 即使延迟执行时间设置为 0,浏览器执行时内部还是会有一个 4 ms 左右的延迟。setTimeout 本身属于异步操作,在 for 循环中会被挂起,继续执行循环。for 循环执行时间显然要比 4ms 短,在 for 循环执行结束(此时 i 值为 10)后,setTimeout 才到 4 ms,此时开始将 function() 回调函数依次添加到任务中去执行。所以输出的是 10 个 10。

在寻找原因的过程中,发现有篇文章总结得特别好:setTimeout 和 setInterval。里面比较详细的讲到了 setInterval 的一些问题和 setTimeout 的扩展使用。一般来说,使用超时调用是模拟间歇调用的一种最佳模式,在开发环境下很少用间歇调用。这里的超时调用指的是 setTimeout,间歇调用指的是 setInterval 。

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »