这篇文章上次修改于 258 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

setInterval 是很常用的一个 JS 方法,但在某些情形下,我们会反复启用 / 停止它的操作。因此 setInterval 需要被赋值给一个变量,这样才可以使用 clearInterval 方法停止它的执行。

我写了个简单的 Demo,在执行 action.start() 后开始自增 num,执行 action.end() 停止循环。

var num = 0;
var timer;

var action = {
    start: function () {
        timer = setInterval(function () {
            num++;
            console.log(num);
        }, 1000);
    },
    end: function () {
        clearInterval(timer);
    }
}

执行了一波后发现,这段代码确实可以控制它的正常启停。但如果我一次性执行两次 action.start(),之后再运行 action.end() 呢?控制台在一秒内出现了两个输出,很明显就不合理了。

1
2

假设这个 action.start() 被绑定在了一个“开始”按钮的点击事件,用户狂点了这个按钮,不就在一秒钟输出 N 次了🐎?

那么我们该如何解决这样的问题呢?最简单的方法就是给 timer 变量设置 setInterval 定时器之前,先看看先前有没有被设置过。

var num = 0;
var timer;

var action = {
    start: function () {
        if(!timer){
            timer = setInterval(function () {
                num++;
                console.log(num);
            }, 1000);
        }
    },
    end: function () {
        clearInterval(timer);
    }
}

这样一改,这段代码看起来确实能在 timer 没设置的情况下,才会进行定时器的设置。但如果我在定时器运行的时候执行 action.end(),再执行 action.start() 呢?

Timer:不好意思啊,我现在的值不为空,所以不运行定时器哦!

可以看出,clearInterval() 确实停止了定时器,但是并不会同时清除变量的值。很多人这个时候一想,我给它赋值 undefined 不就好了嘛。

end: function () {
    clearInterval(timer);
    timer = undefined;
}

这样的操作的确解决了问题,但是这并不是最优雅的写法,保罗在这里建议直接采用赋值的操作来实现,也就是这样:

var num = 0;
var timer;

var action = {
    start: function () {
        if(!timer){
            timer = setInterval(function () {
                num++;
                console.log(num);
            }, 1000);
        }
    },
    end: function () {
        timer = clearInterval(timer);
    }
}

这样写是不是看起来优雅了不少?没想到吧,哈哈哈。其实 clearInterval() 本身是会返回 undefined 的,所以直接赋值就可以了!