1

I have three functions:

let timeVar;
let savedFunctionCode;

function startTimer(code) {
savedFunctionCode = code;
timeVar = setTimeout(savedFunctionCode, 2000);
}

function resumeTimer(intervalTime = 2000) {
setTimeout(savedFunctionCode, intervalTime);
}

function stopTimer() {
clearTimeout(timeVar);
}

The sole purpose of this is basically a way to pause and resume specific code.

Now after the timer is instantiated (by calling startTimer) there is the ability to pause or resume the code.

The intended behaviour of pausing and resuming code execution works IF the methods stopTimer() and resumeTimer() are called at least two seconds apart from each other.

However, if resumeTimer() and stopTimer() in that order are called less than two seconds of each other, stopTimer() will not successfully stop/pause resumeTimer() anticipated execution.

My theory:

In a paused state, when resumeTimer is being called, the code gets executed in two seconds. However if you quickly execute the stopTimer() there is essentially nothing to stop because the code execution from resumeTimer has not started yet. (Less than two seconds).

So in two seconds resumeTimer() method executes its code as stopTimer() does not impact it.

Question: Is there a way in JavaScript so when I execute stopTimer() it would cancel all pending code executions. So in this case I would like stopTimer() to cancel resumeTimer() code execution that would happen in 2 seconds.

Please say if this was unclear.

EXAMPLE:

<html>
<body>
 <div id="media-holder">
<span id="play-button" onclick="resumeTimer();"></span>
<span id="pause-button" onclick="stopTimer();"></span>
</div>


<script>
let timeVar = setTimeout(execute, 2000); 

function resumeTimer(intervalTime = 2000) {
    setTimeout(execute, intervalTime);
}

function stopTimer() {
    clearTimeout(timeVar);
}

function foo() {
    for(let i = 0; i < 100; i++) {
        console.log("execute");
    }
}

</script>
 <html>

IF you rapidly click the play-button and pause-button, it would still continue the execution of foo() method,

Bergi
  • 513,640
  • 108
  • 821
  • 1,164
bob9123
  • 663
  • 8
  • 24
  • Can you please provide a [MCVE]? Seeing the problem you describe actually happening would be tremendously helpful in explaining what's wrong and what you're expecting instead. – Patrick Roberts Feb 23 '18 at 15:29
  • I have updated my question. – bob9123 Feb 23 '18 at 15:56
  • Possible duplicate of [What is the JavaScript version of sleep()?](https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep) – Daniel Netzer Feb 23 '18 at 16:02

1 Answers1

1

JavaScript is single-threaded. You cannot interrupt a function in the middle of execution, since it is blocking the thread from invoking the onclick callback until its execution is completed.

However, you can design an interruptable function using a generator:

function resumeTimer() {
  task.resume();
}

function stopTimer() {
  task.pause();
}

// the `*` means this is a generator function
function* foo() {
  let i = 0;

  while (true) {
    // every `yield` statement is a point
    // where control-flow is interrupted
    yield console.log(i++);
  }
}

class Task {
  constructor(iterator, ms = 16, autoplay = true) {
    this.step = this.step.bind(this);

    this.iterator = iterator;
    this.ms = ms;

    if (autoplay) {
      this.resume();
    }
  }

  step() {
    this.result = this.iterator.next((this.result || {}).value);
  }

  pause() {
    if (this.ref) {
      clearInterval(this.ref);
      this.ref = null;
    }
  }

  resume(ms = this.ms) {
    if (ms !== this.ms) {
      this.pause();
      this.ms = ms;
    }

    if (!this.ref) {
      this.step();
      this.ref = setInterval(this.step, this.ms);
    }
  }
}

let task = new Task(foo());
<button id="play-button" onclick="resumeTimer();">Play</button>
<button id="pause-button" onclick="stopTimer();">Pause</button>

References

Patrick Roberts
  • 40,065
  • 5
  • 74
  • 116
  • Thanks, I will see this approach. I have been researching into Promises, how could they effect this too? – bob9123 Feb 23 '18 at 18:12
  • @DylanWhite you could use `async/await` in a similar way as `function* / yield`, but writing a method for `async/await` that can stall the control-flow for the function indefinitely is not as simple, and if I'm not mistaken, an `async` function with an infinite loop can never be marked for garbage collection since the rest of its control-flow is dependent on a pending promise. – Patrick Roberts Feb 23 '18 at 18:16
  • One quick question, is there a way to make it so it starts instantly? Right now it starts after the duration of 'ms' variable. Is there a way to make it start straight away and after iterate in consistently by 'ms' – bob9123 Feb 23 '18 at 19:32
  • If I wanted to change the interval time of execution while its executing would it be as simple as calling the resume function but with an argument declaring time and passing it to the setInterval argument? – bob9123 Feb 23 '18 at 20:00
  • @DylanWhite if you have any other requests, please ask a new question. – Patrick Roberts Feb 23 '18 at 20:04