Create a fake setTimeout that should work similar to the original setTimeout method.
MY_TIMER.setTimeout(() => { console.log(1) }, 2500); MY_TIMER.setTimeout(() => { console.log(2) }, 2000); MY_TIMER.run(); Output: 2 // will be printed after 2 seconds 1 // will be printed 500 milliseconds after the 1st.
Well, there is no definite way to implement the custom setTimeout, but we can do a workaround.
Create a custom object with that will have setTimeout
, clearTimeout
, and run
method.
In the setTimeout
, store each entry in the queue, for the delay add the input to the current time, to determine when it should be invoked. Also after each entry sort the queue in ascending order based on the time. Return a unique id at the end.
Using the timer id, we can remove the entry from the queue in clearTimeout
.
In the run
method, we will run an infinite while loop, in each iteration, we will get the first element from the queue (as it will be with the least time), check if its time is past the current time then invoke it, else push it back into the queue.
Do it for all the entries in the queue. Add a condition to check if there are no more timers (the queue is empty) to run then break the loop.
const MY_TIMER = { timerId: 1, queue: [], // create a new timer setTimeout: function(cb, time, ...args){ const id = this.timerId++; // add a new entry to the queue // the time at which it will run // will be added to the current date // so that it will run next this.queue.push({ id, cb, time: Date.now() + time, args, }); // sort the queue in the ascending order of time this.queue.sort((a, b) => a.time - b.time); // return the id return id; }, // to stop the timer clearTimeout: function(removeId) { // remove the entry with the given id this.queue = this.queue.filter(({ id }) => id !== removeId); }, // start running the timer run: function() { // this will continuously run the loop // till all the entry in the queue are invoked while(true) { const entry = this.queue.shift(); const { cb, time, args } = entry; // if time hass passed // invoke it if(Date.now() > time){ cb(...args); } // else push it back into the queue else{ this.queue.unshift(entry); } // if there are no further entries // break the loop if(this.queue.length === 0){ break; } } } };
Input: MY_TIMER.setTimeout(() => { console.log(1) }, 2500); MY_TIMER.setTimeout(() => { console.log(2) }, 2000); MY_TIMER.setTimeout(() => { console.log(3) }, 2500); MY_TIMER.setTimeout(() => { console.log(4) }, 3000); MY_TIMER.run(); Output: 2 1 3 4