Pomodoro Clock ClearInterval Not working?

So im having trouble getting the “Start” button when pressed to actually CLEAR out the timer function.


(you will probably need to expand)
Code is above: First of all yes the CSS is SUPER basic, but i generally just throw some buttons/etc… on the screen first to make sure stuff works THEN pretty it up :).

Basically when pressing the start button it should start the clock and then set the “stop” variable equal to “true” and then clear the interval. However it doesn’t seem to be doing that. I should be able to clear and set the interval

Any suggestions? This seems like it should be simple and it should work as is, as the else statement is getting called…but the timer isn’t actually stopping.

The problem is the scope of your timer variable. You should declare your timer id (x) outside of the function, then set the value inside the function so that it doesn’t get reset on each function call. Then when you click the Start button and the function runs again, the value is still set.

Your problem is here …

$('#start').click(function() {
  if(stop == false){ 
    var x = setInterval(tickTock,1000);
    stop = true;
  }
  else{
    console.log("Stop!");
      clearInterval(x);
      stop = false;
  }
}

You declare x inside your if section, so when you get to the else section x is meaningless, it doesn’t point to the interval. You need to move it outside so it will be visible.

var x;
$('#start').click(function() {
  if(stop == false){ 
    x = setInterval(tickTock,1000);
    stop = true;
  }
  else{
    console.log("Stop!");
      clearInterval(x);
      stop = false;
  }
}

Ah i see, I guess im confused why? or since im declaring it everytime it’s basically resetting a new set-interval whenever I press “Start”?

It has to do with scope. Scope flows down to children but not up to parents. When you declare x inside that if statement, it only exists inside that if statement or it’s children. It ceases to exist after you leave that if statement.

I think what’s happening in your else statement is that x doesn’t exist so JS creates it, but it isn’t the x that you think it is so clearInterval tries to stop and interval that doesn’t exist, certainly not the one you started.

If you want that else statement to have access to x, then x needs to be declared somewhere upstream, in a “parent” section of code.

That’s not the case with var statements in javascript. What you are referring to is block scoping - Javascript only gained those in ES6 with the let and const keywords. var statements declarations are always hoisted to the top of their parent function. So, in this case, the var x is declared at the top of the function and will be available throughout (though perhaps not initialized with a value).

The issue, as you stated, is that it x re-created with each invocation of the click function.

This means that clearTimeout has no valid timeout reference to clear and, thus, doesn’t work.

setTimeout returns an ID which can be used by clearTimeout to later cancel the timer. By creating a new ID each time, you lose reference to your previous timer ID and lose the ability to cancel it. You need to store that ID somewhere external to the function so that you can reference it again later.

More on setTimeout here, by John Resig, the original author of jQuery:

http://ejohn.org/blog/how-javascript-timers-work/

OK, thank you, clearly my understanding of JS scope needs some work (having studied programming years ago, how JS handles scope is bizarre).

Trying to understand what you’re saying, I wrote the following code:

for (var i = 0 ; i <= 1 ; i++) {
  if (i == 0) {
    var x = 42;
    console.log("if x = " + x);
  } else {
    console.log("then x = " + x);
  }
}

Consistent with what you’ve said, it outputs:

if x = 42
then x = 42

Interestingly, if I reverse the logic:

for (var i = 0 ; i <= 1 ; i++) {
  if (i == 0) {
    var x = 42;
    console.log("if x = " + x);
  } else {
    console.log("then x = " + x);
  }
}

Then x is undefined in the else statement - codepen returns:

then x = undefined
if x = 42

And x is still availible outside of that block:

for (var i = 0 ; i <= 1 ; i++) {
  if (i == 0) {
    var x = 42;
    console.log("if x = " + x);
  } else {
    console.log("then x = " + x);
  }
}
console.log("outside x = " + x);

yields …

if x = 42
then x = 42
outside x = 42

I think my old Pascal teacher just rolled over in his grave.

But thanks for the clarification. I’m almost to that book in the YDKJS series.

What you want to look up is variable hoisting.

Essentially, when a function is prepared for execution, the JS engine parses the function and looks for any variable declarations. Those are all made, but not initialized, prior to any other code being executed. That’s what is meant by “hoisting”. All variables are declared prior to other code being run, regardless of where they occur in the function (unless they are nested in some sub-function).

Actual initialization of the variable with a value does not occur until the specific line in the code. (In your case inside your if/else blocks). This is why, in your second example, “then x = undefined”. The variable was declared, but not initialized with a value, before you accessed it.

The other thing to keep in mind regarding scoping is simply that, for the most part, Javascript uses function scoping. A variable declared inside of a function cannot be accessed from outside of the function. It’s a pretty simple rule and very useful, I’ve found. The new exceptions to that are the let and const keywords - they are block scoped.

A few references:



Thanks all! It makes much more sense. Im going to go back through and rewrite the entire thing better anyways it was a sloppy mess to begin with ha.

I also meet the same problem, I have defined the variable myInterval which is the return value of “setInterval(myTimer,1000);” as a global variable at the beginning of the function. when I click the clock so that to stop the clock, the “clearInterval(myInterval)” does not work and the clock goes on.
here is my code:

Please give me some guidance, thanks a lot!

I finally got around to looking at this. I guess you got it working because it seems to work now.