CryMasK CryMasK - 1 month ago 11
Javascript Question

Javascript - clearInterval not working when multiple setInterval

I got some problem with setInterval & clearInterval.

In my code, I set multiple intervals, and when count reduce to 0, stop the execution.

Like below:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0" charset="utf-8">
</head>
<body>
<body>
<script type="text/javascript">
for (var i=0; i<4; i++){
var count = 100;

var IntervalID = window.setInterval((function(){ // closure
var timeoutID = IntervalID; // temp
var countTemp = count; // temp
var id = i;

return function(){
countTemp --;
console.log(id + " " + countTemp);

// do something here

if ( countTemp == 0 ){
clearInterval(timeoutID); // stop the execution
console.log(id + " stop");
}
}
})(), 20);
}
</script>
</body>
</html>


After the console appear the stop message "x stop", all element stop except the last element(id:3), it still going.

I try to write my code in another form:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0" charset="utf-8">
</head>
<body>
<script type="text/javascript">
for (var i=0; i<4; i++){
doSomething(i);
}

function doSomething(id){
var count = 100;

var IntervalID = window.setInterval((function(){ // closure
var timeoutID = IntervalID; // temp
var countTemp = count; // temp

return function(){
countTemp --;
console.log(id + " " + countTemp);

// do something here

if ( countTemp == 0 ){
clearInterval(timeoutID); // stop the execution
console.log(id + " stop");
}
}
})(), 20);
}
</script>
</body>
</html>


But this time, all elements don't stop.

I have two questions:

1. What is difference between these two code?

2. How to make the code work fine?

Edit:

If you just want to make the code work, only change one line in the second snippet:

clearInterval(timeoutID); // stop the execution


to

clearInterval(IntervalID); // stop the execution


But other people's answer can solve what I confuse at this problem.

Answer

The problem is that the correct IntervalID is not being captured in your closure, by the time your closure runs, window.setInterval hasn't returned the id as the assignment expression has not finished yet.

A simple trick can be used with an object, since they are passed to functions by reference in JavaScript

I have modified the loop to accomplish this

for (var i=0; i < 4; i++){

    var count = 100;

    var args = { id: i, counter: count };
    var IntervalID = window.setInterval((function(args){ // closure

        return function(){
            args.counter--;
            console.log(args.id + " " + args.counter)
            if ( args.counter == 0 ){                                  
                clearInterval(args.IntervalID); // stop the execution
                console.log(args.id + " stop");
            }
        }.bind(args);
    })(args), 20);

    // by now the correct IntervalID will be captured
    // as the assignment expression has finished executing
    args.IntervalID = IntervalID; 
}