Good afternoon! Here's our prompt for today.
Mastering Time Control in Browsers with window.clearAllTimeouts
Imagine you have the power to control time in your browser. You can schedule events to happen in the future and even cancel them before they occur. This is exactly what window.setTimeout()
and window.clearTimeout()
allow you to do!
Scheduling a Future Event with setTimeout
Let's say you want to display a message that pops up after 5 seconds. You can do this by scheduling a function to run at a future time using window.setTimeout()
. Here's how it's done:
1const alertInFive = () => {
2 window.alert("This will show up after 5 seconds!");
3};
4
5const newTimeout = setTimeout(alertInFive, 5000);
Canceling a Scheduled Event with clearTimeout
What if you have second thoughts and decide you don't want that message to pop up? No worries, you can cancel the scheduled function using window.clearTimeout()
.
1const newTimeout = setTimeout(alertInFive, 5000);
2window.clearTimeout(newTimeout);
A New Challenge: Clearing All Timeouts
Now, let's level up. What if you have multiple functions scheduled and you want to cancel them all? Your mission, should you choose to accept it, is to create a function called window.clearAllTimeouts()
.
When invoked, this function will clear every timeout on the page. Here's what the usage would look like:
1setTimeout(func1, 500);
2setTimeout(func2, 500);
3setTimeout(func3, 500);
4setTimeout(func4, 500);
5
6window.clearAllTimeouts();
7// No scheduled functions run!

Your task is to write this utility function. It's like being a time-controlling superhero for your browser! Are you up for the challenge?
Try to solve this here or in Interactive Mode.
How do I practice this challenge?
xxxxxxxxxx
// Assuming window object in a Node.js environment for demonstration purposes.
global.window = {
timeouts: [],
setTimeout: function(callback, delay) {
const id = Math.random(); // Random ID for demonstration; usually, you'd use a more deterministic way
this.timeouts.push({ id, callback, delay });
return id;
},
clearTimeout: function(id) {
this.timeouts = this.timeouts.filter(timeout => timeout.id !== id);
},
clearAllTimeouts: function() {
// Your implementation goes here
},
// Utility method to emulate 'tick' of the event loop
_tick: function() {
this.timeouts.forEach(timeoutObj => timeoutObj.callback());
}
};
// Test cases for window.clearAllTimeouts
function runTests() {
let test1Flag = false;
let test2Flag = false;
// Schedule some timeouts
const timeout1 = window.setTimeout(() => { test1Flag = true; }, 1000);
const timeout2 = window.setTimeout(() => { test2Flag = true; }, 1000);
Here's how we would solve this problem...
How do I use this guide?
Keeping Track of Timers
The primary challenge here is how to maintain a list of all active timers in the window object. Our aim is to be able to loop through this list and cancel each timer using window.clearTimeout
.
Utilizing Sets for Efficient Tracking
We'll use a Set, aptly named timers
, to hold timer IDs. Sets are a data structure that allow us to enjoy near-constant time for both insertion and deletion.
1const timers = new Set();
Storing Native Functions
Before we create custom wrapper functions around window.setTimeout
and window.clearTimeout
, it's essential to save the native implementations. We'll store these in variables named window.nativeSetTimeout
and window.nativeClearTimeout
.
1const timers = new Set();
2window.nativeSetTimeout = window.setTimeout;
3window.nativeClearTimeout = window.clearTimeout;
Crafting Wrapper Functions for Timer Management
Now let's get creative! We can write custom wrapper functions around window.setTimeout
and window.clearTimeout
. These wrappers will have an additional duty: tracking new timers. When a new timer is created, its ID will be added to our Set. Similarly, we'll remove IDs when timers are cleared or completed.
1window.setTimeout = (cb, time, ...args) => {
2 const cbWrapper = () => {
3 cb(...args);
4 // No longer need to track once completed
5 timers.delete(id);
6 };
7 const id = window.nativeSetTimeout(cbWrapper, time);
8 timers.add(id);
9 return id;
10};
11
12window.clearTimeout = (id) => {
13 window.nativeClearTimeout(id);
14 timers.delete(id);
15};
In these wrapper functions, we use the native implementations to actually set and clear the timeouts. Our added functionality is simply to manage the timer IDs using the timers
Set. This way, when you need to clear all timeouts, you can easily loop through this Set and clear each one.
Implementing the Clear-All Mechanism
Now that we've got a way to keep track of all active timers, implementing the clearAllTimeouts
function becomes a straightforward task.
Leveraging the Set for Mass Cancellation
The core idea is to simply loop through our timers
Set and use the native clearTimeout
function on each timer ID stored in it. This will effectively stop all the timers, and your window will be free from any lingering timing events.
1const timers = new Set();
2window.nativeSetTimeout = window.setTimeout;
3window.nativeClearTimeout = window.clearTimeout;
4
5// The magic happens here
6window.clearAllTimeouts = () => {
7 for (const id of timers) {
8 window.clearTimeout(id);
9 }
10};
11
12window.setTimeout = (cb, time, ...args) => {
13 const cbWrapper = () => {
14 cb(...args);
15 // No more tracking needed
16 timers.delete(id);
17 };
18 const id = window.nativeSetTimeout(cbWrapper, time);
19 timers.add(id);
20 return id;
21};
22
23window.clearTimeout = (id) => {
24 window.nativeClearTimeout(id);
25 timers.delete(id);
26};
In this setup, the clearAllTimeouts
function leverages the existing timers
Set to halt all the active timers. Since we've been diligent in tracking every new timer and removing each one that gets cleared or completed, this Set will always be current. As a result, clearAllTimeouts
becomes a powerful tool to halt all timers with a single call.
One Pager Cheat Sheet
- With
window.setTimeout()
andwindow.clearTimeout()
, you can schedule and clear timeouts, respectively, but can you write a method,window.clearAllTimeouts
, to clear multiple timeouts at once? - We have overwritten the native
window.setTimeout
andwindow.clearTimeout
functions toadd
andremove
timer IDs to/from aSet
collection, in order to implement a customclearAllTimeouts
function. ClearAllTimeouts
iterates
througheach timer
andmanually clears
it.
This is our final solution.
To visualize the solution and step through the below code, click Visualize the Solution on the right-side menu or the VISUALIZE button in Interactive Mode.
xxxxxxxxxx
const timers = new Set();
window.nativeSetTimeout = window.setTimeout;
window.nativeClearTimeout = window.clearTimeout;
window.clearAllTimeouts = () => {
for (const id of timers) {
clearTimeout(id);
}
};
window.setTimeout = (cb, time, args) => {
const cbWrapper = () => {
cb(args);
timers.delete(id);
};
const id = nativeSetTimeout(cbWrapper, time);
timers.add(id);
return id;
};
window.clearTimeout = (id) => {
nativeClearTimeout(id);
timers.delete(id);
};
You're doing a wonderful job. Keep going!
If you had any problems with this tutorial, check out the main forum thread here.