Beginner’s Guide to setTimeout in JavaScript

Jacinto Wong
Jacinto Wong
hero image

Have you ever written some JavaScript code, hit run, and then things just don’t happen in the order you thought they would.

Maybe a message logs too late, an action runs too soon, or something just disappears into the void.

It sucks right?

Well, the good news is there’s a solution to this called setTimeout, and it’s fairly easy to use once you know how it works.

In this guide I’ll walk you through what setTimeout really does, why it matters, and how to use it without getting tripped up. Once it clicks, a lot of other confusing stuff in JavaScript suddenly makes more sense.

Sidenote: If you want to learn more about JavaScript, be sure to check out Andrei’s Complete Web Developer course, as well as my Beginner and Advanced JavaScript projects:

learn javascript

We have everything you need to become a full-stack JavaScript developer in 2025.

Graduates from these programs are now working at Google, Tesla, Amazon, Apple, IBM, Uber, Facebook, Shopify + other top tech companies. There’s no reason why you couldn’t do the same!

With that out of the way, let’s get into this 5-minute tutorial.

What setTimeout is, why it matters, and how it works

setTimeout is a built-in function that schedules a bit of code to run after a delay that’s measured in milliseconds. You can think of setTimeout as telling JavaScript, “Hey, run this later.”

But what makes it powerful isn’t just the delay. It’s how that delay fits into JavaScript’s asynchronous nature.

This is because JavaScript is single-threaded. It does one thing at a time, line by line.

The problem of course is that sometimes you don’t want everything to happen immediately. Maybe you want to show a loading spinner, delay a notification, or give the UI a chance to update before doing something heavy.

And that’s where setTimeout comes in to save the day.

For example

Here’s the basic syntax:

setTimeout(callback, delay);
  • Callback refers to a function you want to run later
  • Delay is simply how long to wait (in milliseconds) before running it

So if you write:

setTimeout(() => {
  console.log("This runs after 2 seconds");
}, 2000);

JavaScript will wait at least 2 seconds before logging the message.

What’s important to understand is that it doesn’t pause the whole program, it just sets that function aside and keeps going, and lets the rest of your code keep executing while it waits in the background.

For example

Take a look at this code block with a delay added:

console.log("One");
setTimeout(() => {
  console.log("Two");
}, 0);
console.log("Three");

You might think it would print “One, Two, Three”. But it actually prints:

One  
Three  
Two

Why?

Well, this is because even a setTimeout with 0 delay doesn’t run immediately. It just says, “Run this after the current stack of code is done.” So JavaScript finishes everything it’s doing first, then checks the timeout queue.

That’s part of what’s called the event loop, and setTimeout is one of the simplest ways to see it in action.

When would you use setTimeout?

This pattern comes up more than you’d think.

You might use setTimeout to:

  • Delay showing a message or tooltip
  • Wait before retrying a failed network request
  • Create animations or transitions that don’t start immediately
  • Defer a heavy calculation until after the UI has painted

For example

Let’s say that you have a button that when clicked, should show a confirmation message for just a moment:

button.addEventListener("click", () => {
  message.innerText = "Saved!";
  setTimeout(() => {
	message.innerText = "";
  }, 1500);
});

That’s the kind of thing setTimeout was made for, where it lets you show something briefly, then disappear later, without blocking the rest of your app.

One quick note for all you performance optimization fans

setTimeout isn’t a performance booster. It doesn’t make your site load faster or fix your Core Web Vitals score, but it can make things feel smoother.

How?

Well, simply because it gives the browser a chance to paint the UI before running heavier logic. So instead of everything happening at once and freezing the screen, your app feels more responsive. (It’s more of a user experience tool than a true speed upgrade).

If you're looking to really boost performance, you'll want to explore things like lazy loading, requestIdleCallback, or Web Workers. I’ll cover those in a future guide.

But for now, let’s look at something just as important, which is how to actually stop a setTimeout once you’ve started it.

How to cancel a setTimeout

Sometimes you schedule something with setTimeout, but then realize you don’t want it to run after all. Maybe the user navigated away, clicked a different button, or some other condition changed.

Luckily, JavaScript gives you a way to cancel a timeout before it runs with clearTimeout.

Here’s how it works.

When you call setTimeout, it returns an ID, which is basically a reference to the scheduled task. You can store that ID in a variable and then use clearTimeout(id) to cancel it.

For example

const timeoutId = setTimeout(() => {
  console.log("This will never run");
}, 3000);

clearTimeout(timeoutId);

In this case, the setTimeout was scheduled for 3 seconds, but it’s cancelled immediately after, and the callback never runs.

This is especially useful when you’re dealing with interactive elements.

For example

Maybe you want to show a tooltip when the user hovers over something, but if they move their mouse away quickly you don’t want that tooltip to still appear.

let tooltipTimeout;

button.addEventListener("mouseenter", () => {
  tooltipTimeout = setTimeout(() => {
	showTooltip();
  }, 500);
});

button.addEventListener("mouseleave", () => {
  clearTimeout(tooltipTimeout);
});

Here, the tooltip only shows if the user hovers for at least 500ms. If they leave earlier, the setTimeout is cancelled and the tooltip never appears. That gives you much finer control over timed behavior.

Another common use case is for cancelling delayed actions during form validation or multi-step flows, where you don’t want multiple timeouts stacking up if the user keeps interacting.

Just remember:

  • setTimeout always returns a numeric ID (in browsers)
  • clearTimeout(id) only works if the ID still exists
  • If the timeout already finished, clearTimeout does nothing—but also doesn’t throw an error

Handy right?

This makes clearTimeout a safe tool to use even if you’re not 100% sure whether the timeout has already fired.

Common mistakes and best practices when using setTimeout

Although setTimeout is simple on the surface, it's one of those tools that trips people up when they don’t fully understand how JavaScript handles timing.

So let’s walk through some of the most common mistakes and how to avoid them.

Mistake #1. Running the function immediately

One of the most common errors is accidentally calling the function instead of passing it as a reference.

For example

Here’s what that looks like:

setTimeout(doSomething(), 2000); // ❌ Wrong

Notice that this doesn’t wait 2 seconds. Instead, it runs doSomething() immediately, and then passes whatever it returns into setTimeout, which does nothing useful.

The solution is to pass the function reference, or wrap it in an arrow function, like so:

setTimeout(doSomething, 2000);   	// ✅ Right
setTimeout(() => doSomething(), 2000); // ✅ Also fine

If you're not sure whether you're calling the function or passing it, a quick rule of thumb is that if you see parentheses after the name, you’re calling it.

Mistake #2. Not storing the timeout ID

If you ever need to cancel a timeout, you must store its ID. Otherwise, there’s no way to reference it later with clearTimeout.

For example

This is wrong:

setTimeout(() => {
  console.log("Will run, and can’t be cancelled");
}, 3000);

The solution is to always store the timeout if you might cancel it:

const timeoutId = setTimeout(() => {
  console.log("Maybe cancelled");
}, 3000);

// later...
clearTimeout(timeoutId);

Even if you’re not sure you’ll cancel it, it’s a good habit to keep the ID around, especially in interactive apps.

Mistake #3. Assuming it blocks other code

Like I said earlier, some beginners think setTimeout waits before moving on but it doesn’t. It just sets a timer for that part of the code, but keeps going with the rest.

setTimeout(() => {
  console.log("Done waiting");
}, 2000);

console.log("Still running…");

This becomes a bigger deal when you expect things to happen in a specific order but don’t account for the delay. This is why you need to think of setTimeout as a way to schedule some code for later, not as an actual “pause” of the entire code.

Mistake #4. Using setTimeout for repeated actions

It’s common to assume you can use setTimeout in a loop to space things out, but that’s not how it works.

For example

for (let i = 0; i < 5; i++) {
  setTimeout(() => {
	console.log(i);
  }, 1000);
}

At first glance, you might expect this to log one number per second: 0, then 1, then 2, and so on, but that’s not what happens.

Instead, all five setTimeout calls are scheduled at the same time with the same delay, so they all run together after one second.

This means you’ll actually see these numbers printed at once, and not one per second.

0  
1  
2  
3  
4

If you want to delay between each step, you’ll need to use a recursive setTimeout instead:

let i = 0;

function logNext() {
  if (i < 5) {
	console.log(i);
	i++;
	setTimeout(logNext, 1000);
  }
}

logNext();

This way, each call waits a full second before logging the next number. You get one log per second, just as you'd expect from a loop with pauses in between.

Mistake #5. Only using anonymous functions

Arrow functions are convenient, especially for short bits of code. However, when you're using setTimeout in more complex or long-lived code, relying only on anonymous functions can make your code harder to read, debug, or cancel.

For example

const timeoutId = setTimeout(() => {
  message.innerText = "";
}, 1500);

This works fine, but imagine trying to cancel or reuse that logic elsewhere. It would be overly complex because it’s all buried inside the timeout.

The solution is to use named functions when the logic is more than a one-liner or when you might reuse or cancel the timeout:

function hideMessage() {
  message.innerText = "";
}

const timeoutId = setTimeout(hideMessage, 1500);

Named functions make it easier to cancel a timeout later, move the logic into its own file, or even just make your code easier to scan and understand.

Give setTimeout a try in your own projects

As you can see, learning setTimeout is more than just figuring out a timer. It’s your first real look at how JavaScript handles timing, defers work, and reacts over time.

Once you see how it fits into the bigger picture of asynchronous behavior, a lot of other things start to click. (It’s the kind of tool that teaches you how the language thinks which opens up a lot of aha moments).

The best way to understand a new concept though is to try it out for yourself. So go ahead and use setTimeout in one of your own projects. Nothing too fancy, delay a message, cancel one, or create a timed sequence.

You’ll learn way more by playing with it than by just reading about it.

P.S.

Remember, if you want to learn more about JavaScript, be sure to check out Andrei’s Complete Web Developer course, as well as my Beginner and Advanced JavaScript projects:

learn javascript

We have everything you need to become a full-stack JavaScript developer in 2025, build a portfolio, and get hired.

In fact, graduates from these programs are now working at Google, Tesla, Amazon, Apple, IBM, Uber, Facebook, Shopify + other top tech companies. There’s no reason why you couldn’t do the same!

As a ZTM member, you get access to all these courses and more in a single membership.

Plus, once you join, you'll have the opportunity to ask questions in our private Discord community from me, other students and other working tech professionals, as well as access to every other course in our library!


More from Zero To Mastery

How to Become a Full-Stack Web Developer & Get Hired in 2025 preview
How to Become a Full-Stack Web Developer & Get Hired in 2025
32 min read

Learn everything you need to know to become a Full-Stack Web Developer, as well as how to get hired as one in 2025 with this step-by-step guide!

CSS vs HTML: Comparison Guide (With Code Examples) preview
CSS vs HTML: Comparison Guide (With Code Examples)
24 min read

HTML vs CSS. Learn their differences, pros, and cons, and how to use them with different variables for dynamic site creation!

Beginners Guide To Flexbox With Bootstrap preview
Popular
Beginners Guide To Flexbox With Bootstrap
15 min read

Learn how to use Flexbox features for responsive design inside of Bootstrap. I've also included some code examples to show you how easy it is to start using!