Skip to main content

Command Palette

Search for a command to run...

The "Idle" Secret to Faster Apps

How to offload non-critical tasks without the overhead of Web Workers

Updated
4 min read
The "Idle" Secret to Faster Apps

Ever feel like your web app is trying to do too much at once?

You’ve built a pixel-perfect UI, but the moment you trigger a search or an analytics log, the screen stutters for a split second. We often think the only way to fix this is by moving everything to a Web Worker, but that’s like hiring a full-time moving crew just to shift a chair across the room.

The real secret to a buttery-smooth experience isn't about working harder, it’s about working smarter during the browser’s "quiet time" by using requestIdleCallback, you can let the browser handle its chores only when it’s bored, ensuring your users never see a single frame of lag.

Demo Problem

Suppose you're performing a long running task and while that task is running, user wants to register a click. If task is still running, user won't see the click being registered. Let's try to demonstrate it with an example

If you notice above, when you click on the button and then click on select component, it doesn't respond for a moment. It's because the loop is being processed on main thread and it couldn't respond to other user events until it finishes that task.

You may find the sandbox link at the end of the solution.

Demo Solution

Let's tackle the problem with the help of requestIdleCallback (Read more here). It accepts a callback and passes deadline as first argument to the callback. deadline exposes a method called remainingTime which returns the estimated browser idle time remaining. We can make use of these details to schedule our task during the idle period.

In above image rAF stands for requestAnimationFrame (read more about it here) which is used to schedule high priority task, unlike requestIdleCallback which is used to schedule low priority tasks.

Let's see the solution now, focus on the loopWithIdleCallback function and it's usage

With above solution, you'll notice the difference on performance

You can notice that when we clicked on the button to start the loop, it started the looping but if we click on select component, it prioritised that click and responded to that first. Hence we don't see any janky UX.

Here's the sandbox for your reference :)

Why not a Web Worker?

To send data to a web Worker, the browser must clone the data. If you have a massive data, the main thread actually has to work hard just to package that data for the worker. While requestIdleCallback lives on the main thread. It can see your app's variables and state directly. There is zero overhead to start the task.

Feature

Web Worker (The Off-site Contractor)

requestIdleCallback (The In-house Assistant)

Location

Runs on a separate thread (OS level).

Runs on the main thread (UI level).

Communication

Needs postMessage (Data must be cloned).

Direct access (No cloning needed).

Primary Goal

High-intensity CPU math/processing.

Low-priority housekeeping tasks.

When to use which?

  • Use a Web Worker if you have a task that takes more than 50ms and doesn't need to touch the DOM (e.g., processing a high-res photo).

  • Use requestIdleCallback if you have many tiny, non-critical tasks (e.g., sending 50 small analytics pings) that you don't want to interfere with the user's scrolling.

Conclusion

Don’t Outsource What You Can Handle at Home.

As developers, our first instinct for performance issues is often to "throw more threads at it." But in the world of the modern browser, managing the Main Thread is an art form. While Web Workers are incredible for heavy-duty data crunching, they come with a "serialisation tax" and complexity that can sometimes slow you down more than they help.

By embracing requestIdleCallback, you aren't just writing code, you’re being a good neighbour to the browser. You’re letting the user’s interactions take the spotlight while you handle the "invisible housekeeping" in the shadows.

The Golden Rule:

  • If it takes a long time and doesn't need the DOM: Worker it.

  • If it’s a bunch of small things or needs the UI: Idle it.

Resources:

More from this blog