javascript stop setTimeout after containing object deleted or overwritten

Viewed 21

I would like to stop a timer after I delete the variable containing the function that ran it.

The following works but requires an extra step:

foo = (function() {
    function doSomething() {
        console.log('I am running ')
        timer1 = setTimeout(doSomething, 2000)
    }
    doSomething()
    console.log('timer is #' + (bob))
    return {
        stopTimer: function() {
            clearTimeout(timer1)
            return true
        }
    }
})()
// 
// let it run a while..
// 
// later, stop it .. this works but is an extra step
foo.stopTimer()
// no more logs .. success

That is, it stops the timer. However the REAL OBJECTIVE is just to do this:

foo = <new code like a new version overwriting the existing one>
-- or less desirably --
foo = null

And have the timer(s) stop. Is this possible and if so how?

1 Answers

It's possible, but only by using tricks, which I'd highly recommend not doing, because they greatly obfuscate the intent of the code.

By putting foo on the global object (or with with - please don't), you can make it a getter/setter, where the setter will, when invoked, call the stopTimer.

let timer1;
function doSomething() {
    console.log('I am running ')
    timer1 = setTimeout(doSomething, 1000)
}
doSomething();
Object.defineProperty(
  window,
  'foo',
  {
    set(newArg) {
      clearTimeout(timer1);
      // delete this setter
      delete window.foo
      window.foo = newArg;
    },
    configurable: true
  }
);

button.onclick = () => {
  console.log('stopping timer');
  foo = null;
  console.log('new value of window.foo:', foo);
};
<button id="button">stop</button>

A more sensible approach, if your objective is to not to have to both have a line that calls foo.stopTimer and also have a line that creates a new timer (or something) would be to create a method that both stops the timer and creates the new desired one at once, like

//               callback                  interval
foo.makeNewTimer(() => console.log('new'), 1000);
Related