JavaScript async programming

When to Use Async JavaScript?

January 2026 Article

I had this question asked recently: "How do I know which parts of JavaScript are async and which ones aren't?"

You'll find plenty of tutorials that tell you setTimeout is async, fetch is async, and so on. But they usually don't explain the underlying rule that determines what can be async in the first place.

For example, why can I do this:

console.log("This runs first")

setTimeout(() => {
  console.log("This runs later (after 200ms)")
}, 200)

console.log("This also runs immediately - setTimeout doesn't block!")

But not this:

// This BLOCKS everything - even with async/await!
async function expensiveCalculation() {
  let sum = 0
  for (let i = 0; i < 1000000000; i++) {
    sum += i
  }
  return sum
}

const result = await expensiveCalculation() // Still freezes the page!

Here's the key to understanding async Javascript: JavaScript itself is not asynchronous. But operations that happen outside of JavaScript are.

The setTimeout Example

At first glance, setTimeout seems like a core JavaScript feature. But here's the twist: the actual timing mechanism lives outside JavaScript entirely.

When you call setTimeout, here's what really happens:

  1. JavaScript delegates the timing work to the browser runtime. JavaScript itself doesn't do any timing
  2. The browser (not JavaScript) handles the actual timer using its own optimized C++ code
  3. When the timer completes, the browser queues a callback event
  4. JavaScript picks up the event and executes your callback

If you're using Chrome, Chrome is handling the timer. If you're using Firefox, Firefox is handling it. The browser itself is doing the work, not JavaScript.

All the actual work happened outside JavaScript's engine. JavaScript just delegated the problem to the browser and waited for the result. That's why it can be asynchronous, because the heavy lifting happens elsewhere.

The Calculation Example

In contrast, that expensive loop runs inside JavaScript's engine. There's nowhere to offload it. It just blocks the main thread, freezing your entire page.

Even if you mark the function as async and use await, it won't help. The work still happens inside JavaScript's engine, blocking the main thread. The work has to happen outside JavaScript for it to be truly asynchronous.

Other Async Operations

This also applies to async operations like:

  • HTTP requests
  • setInterval
  • Intersection Observer

These all happen outside JavaScript's engine, so they can be asynchronous.

What About localStorage? It's Outside JavaScript Too

Good question! localStorage is a browser feature that happens outside JavaScript's engine. Exactly like setTimeout and fetch. So shouldn't it be async?

Actually, localStorage is synchronous. Even though it happens outside JavaScript, reading and writing to localStorage is performant and typically very fast (it has a 5MB limit and uses the browser's storage system).

However, if you add too much data to localStorage, you might run into performance issues. Since it's synchronous, large write operations can block the main thread, potentially freezing your page. The browser designers decided the trade-offs weren't worth making it async for typical use cases, but be mindful of the amount of data you're storing.