0

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.

3
  • What is IntervalID-s value at the time you trying to use it? Console.log that one out, just below the var timeoutID = IntervalID; Commented Nov 4, 2016 at 16:53
  • 3
    In the first snippet, the timeoutID is undefined for i==0, since the call to setInterval hasn't completed yet. Thus, adding console.log(i + " - " + IntervalID); immediately above var timeoutID = IntervalID; // temp will show you 0 - undefined, then 1 - 1, 2 - 2, 3 - 3 Commented Nov 4, 2016 at 16:54
  • Oh, I understand some part, in the first snippet, when countTemp reduce to 0, clearInterval(timeoutID); actually stop previous one (in id==1 section, it stop id==0 execute; id==2 stop id==1; etc. But no one stop id==3, so it still going). Commented Nov 4, 2016 at 17:50

1 Answer 1

1

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; 
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, now I understand more clearly. Answer my own question 1, in the first snippet, timeoutID capture previous IntervalID that remain in memory, so only last one can't stop. In the second snippet, call one function and pop from founction stack after it finish, so timeoutID can't capture any value, it is undefined, all elements/intervalIs can't stop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.