Implement clearAllTimeout in JavaScript

It is an extremely common question asked in JavaScript Interviews, where we are asked to implement the clearAllTimeout function.

ClearAllTimeout clears all the setTimeout which are active.

setTimeout is an asynchronous function that executes a function or a piece of code after a specified amount of time.

setTimeout method returns a unique Id when it is invoked, which can be used to cancel the timer anytime using the clearTimeout method which is inbuilt.

Reading about the problem statement we can understand that all we have to do is to clear all the active timers and the same can be done by clearing all timeoutIds using clearTimeout.

window.clearAllTimeout = function(){
  //clear all timeouts
  while(timeoutIds.length){
    clearTimeout(timeoutIds.pop());
  }
}

But to clear all the timeoutIds at once, we will need to store them somewhere, let’s say in an array. For which we will override the existing setTimeout method and collect all the timeoutIds in an array.

window.timeoutIds = [];

// store the original method
const originalTimeoutFn = window.setTimeout;

//over-writing the original method
window.setTimeout = function(fn, delay) { 
  const id = originalTimeoutFn(fn, delay);
  timeoutIds.push(id);
  
  //return the id so that it can be originally cleared
  return id;
}

Complete code

window.timeoutIds = [];

// store the original method
const originalTimeoutFn = window.setTimeout;

//over-writing the original method
window.setTimeout = function(fn, delay) { 
  const id = originalTimeoutFn(fn, delay);
  timeoutIds.push(id);
  
  //return the id so that it can be originally cleared
  return id;
}

window.clearAllTimeout = function(){
  //clear all timeouts
  while(timeoutIds.length){
    clearTimeout(timeoutIds.pop());
  }
}

If we test this, this runs as expected. It will clear all the timeouts, as setTimeout is an Asynchronous function, meaning that the timer function will not pause execution of other functions in the functions stack, thus clearAllTimeout runs and cancels them before they can be executed.

setTimeout(() => {console.log("hello")}, 2000);
setTimeout(() => {console.log("hello1")}, 3000);
setTimeout(() => {console.log("hello2")}, 4000);
setTimeout(() => {console.log("hello3")}, 5000);

clearAllTimeout();

If you notice, here we have added a global variable timeoutIds which we are using to store the ids of each setTimeout and later to cancel all of them, using the global variable is bad practice as it can be overridden.

One thing you could do over here is to wrap these inside a closure or higher-order function or an Object to keep it restricted.

This way we won’t be interfering with existing methods and can still get our work done.

const MY_TIMERS = {
    timeoutIds : [],//global timeout id arrays
    //create a MY_TIMERS's timeout
    setTimeout : function(fn,delay){
        let id = setTimeout(fn,delay);
        this.timeoutIds.push(id);
        return id;
    },
    //MY_TIMERS's clearAllTimeout
    clearAllTimeout : function(){
        while(this.timeoutIds.length){
          clearTimeout(this.timeoutIds.pop());
        }
    }
};
Input:
const id = MY_TIMERS.setTimeout(() => {console.log("hello")}, 1000);
console.log(id);
MY_TIMERS.clearAllTimeout();

Output:
13 //timeoutId