CryMasK
CryMasK

Reputation: 303

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.

Upvotes: 0

Views: 1712

Answers (1)

Sow OBM
Sow OBM

Reputation: 58

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; 
}

Upvotes: 1

Related Questions