Long Tasks: What they are and why you should avoid them<!-- --> | <!-- -->Web Performance Tips

Long Tasks: What they are and why you should avoid them

All web applications are granted a single thread, the Main Thread, which is responsible for:

  • Handling user input events, like clicks and keyboard events
  • Running JavaScript tasks, like React or other client business logic
  • Generating frames to present pixels to the user

Each of these operations is executed in what's known as a Task.

Since there is only one Main Thread responsible for all these Tasks, any Task that takes a particularly long time to execute will clog up the thread and degrade user experience.

In this tip, we'll examine these long-running Tasks, called Long Tasks, and why you should avoid them.

Prerequisites

What is considered a Long Task?

A Task is considered a Long Task if it takes longer than 50ms.

A diagram showing two Tasks, one Long Task and one Short Task

How Long Tasks degrade the Main Thread

As we know from my tip on the browser event loop, the Main Thread can only run one Task at a time. Any Task that is not actively running is queued in the browser's Task Queue:

A diagram showing a Long Task running on the Main Thread, and other Tasks queued in the Task Queue

While a Task is executing on the Main Thread, the Event Loop can not unload other queued Tasks from the Task Queue onto the thread.

Long Tasks are particularly problematic because they block the Event Loop from unloading the Task Queue for an extended period of time; they essentially block the Event Loop from executing any further work on the Main Thread.

Frame Degradation

The browser event loop occasionally will run the Render Steps instead of selecting a Task from the Task Queue. The Render Steps Task is responsible for presenting frames to the user's screen.

A diagram showing the Render Steps interleaved with Tasks on the Main Thread

Like other Tasks, the Render Steps cannot run while another Task is running on the thread. As a result, a Long Task can severely degrade the browser's ability to generate frames to your user:

A diagram comparing a short task and a long task with a frame produced

Problem: Delaying your Initial Frame

If your web application relies on JavaScript to produce your initial UI on page load, the speed to present your critical frame will depend on the speed of the JavaScript required to present it.

For example, if your app relies on React to present its initial frame, React must construct the DOM, and then the Render Steps must run, and then finally your user can see your UI:

A diagram showing React running in a Long Task and producing a frame

Your user cannot see your UI until a Frame is produced, so it's important to reduce the size of your Long Task so the browser can produce the frame sooner:

A diagram showing React running in a short Task and producing a frame

Problem: Degrading Interactivity

Let's consider another example: a user is typing into an input box.

Each keypress event is queued in the browser's Task Queue and subsequently place onto the Main Thread to run by the Event Loop. The keypress is then represented on-screen via a Frame:

A diagram showing input being received, interleaving with frames

We want input to feel responsive and smooth for users, like this:

An animation showing smooth typing

Notice that each keypress of the user is immediately represented as pixels on the screen via a Frame.

If a Long Task occurs while typing, your user will experience jank:

A diagram showing input being received, with long tasks between frames

For a user, input jank will manifest as delayed frames to reflect their input events:

An animation showing jank during typing

What causes Long Tasks?

Long Tasks typically arise from heavy, slow, or inefficient JavaScript codepaths that are synchronous within a Task.

Common examples of these codepaths include:

  • while / for loops with a high iteration count
  • Synchronous JavaScript work, often in high frequency, such as:
    • String parsing, decoding, concatenation, etc.
    • Updates to the DOM
    • Compilation of large scripts
  • Inefficient querying of element positioning information, inducing Layout Thrashing
  • Heavy or frequent Microtasks, usually from resolved Promises

Long Tasks do not only manifest to JavaScript related work, but in my experience, this is their most common source.

Identifying Long Tasks In the Profiler

If you collect a trace of your web application, the Chromium F12 Profiler will help you identify Long Tasks by flagging them in the UI:

The Chromium F12 Profiler highlighting Long Tasks

The profiler will represent Long Tasks as a flamegraph. Follow my tip on understanding flamegraphs to learn how to read these graphs, and identify slow codepaths within a Task.

Conclusion

We've covered what Long Tasks are, and why you should avoid them.

Explore the following tips on how to optimize your Long Tasks and improve your user experience:

That's all for this tip! Thanks for reading! Discover more similar tips matching Browser Internals and JS Optimization.