Yosh
Yosh

Reputation: 2742

returning setTimeout to stop later doesn't work as my expectation?

Here's a simple html&javascript: When I click on the "start" button, the counter starts, the number displayed being incremented, then when I click on the "start" again, the counter resets and starts all over again. (This is just a practice with setTimeout and I don't intend to use this as anything.) At first I forgot to stop mainloop and was running another mainloop every time the button is clicked, which resulted in accelerated counting after repeated clicks. I saw this question (javascript - How to stop a setTimeout loop?) and managed to make it work.

And then I changed the javascript slightly. I thought these codes are almost equivalent, but it wasn't --- it no longer worked, multiple mainLoop seemed to be running after clicks. My question: why are these not equivalent? Why isn't the latter working?

Working codes:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <div>
    <pre id="start" style="background-color:green; width:70px; text-align:center;">Start</pre>
    <pre id="count"></pre>
  </div>
  <script src="main.js"></script>
</body>
</html>

main.js

var counter = 0;
var timer;

function mainLoop(){
  counter++;
  document.getElementById("count").innerHTML=counter;
  timer = setTimeout(mainLoop,100);
}

function start(){
  if (timer){
    // stop mainLoop that is currently running.
    clearTimeout(timer);
  }
  // and start again.
  counter = 0;
  mainLoop();
}

document.getElementById("start").addEventListener("click",start);

Then I changed:

var counter = 0;
var timer;

function mainLoop(){
  counter++;
  document.getElementById("count").innerHTML=counter;
  return setTimeout(mainLoop,100); // changed here
}

function start(){
  if (timer){
    clearTimeout(timer);
  }
  counter = 0;
  timer = mainLoop();  // and here
}

document.getElementById("start").addEventListener("click",start);

Upvotes: 0

Views: 150

Answers (4)

iLikePrograms
iLikePrograms

Reputation: 468

The reason you are getting multiple mainLoop's is because in the mainLoop, you are telling it to call itself every 100 milliseconds. Then it's returning setTimeout to itself, instead of returning it to the start method.

So you end up calling setTimeout more than once, but you arent storing the return value, which you need to pass to clearTimeout to cancel the loop.

What you could do is have something like the following:

function mainLoop() {
    counter++;
    document.getElementById("count").innerHTML=counter;
}

function start() {
    if (timer){
        clearTimeout(timer);
        timer = undefined;
        counter = 0;
    } else {
        timer = setInterval(mainLoop(), 100); // Set interval calls it every 100 milliseconds until it is cancelled
}

document.getElementById("start").addEventListener("click", start, false);

Upvotes: 1

Sjoerd de Wit
Sjoerd de Wit

Reputation: 2413

You execute clearTimeout(timer) before you set timer = mainLoop();

also i believe timer = mainloop() just runs the mainLoop function again timer is only the timeout function..

it look's like you're using setTimeout as an interval maybe you should look at this..

jQuery setInterval()

Upvotes: 1

Evan Knowles
Evan Knowles

Reputation: 7501

Your code will work the first time mainLoop is called as the value is returned. The second time it is called it is called from setTimeout, which means that the returned value (the value of the new timeout) is lost.

When you try to clear the timeout, you're trying to clear it using the value obtained from the very first call, which is a timeout which is passed in any case, not the current timeout value.

Try setting timer in your mainLoop.

Upvotes: 1

Aliendroid
Aliendroid

Reputation: 515

mainLoop is Looping itself, without setting the timer that's why.

Every-time the setTimeout get a new value , while you are stopping a old Timer if you don't update it.

You may wanna look into setInterval() instead thou, don't need repeatedly create Timer.

Upvotes: 2

Related Questions