skip to content

Long Tasks and the Main Thread

Anything over 50ms on the main thread blocks input, animation and paint at once. Interviewers want the definition, the usual causes, and a concrete plan to break the work up.

on this pageshow

questions

5

In web performance, what counts as a "long task" on the browser's main thread, why is the threshold 50 ms rather than a frame's 16 ms, and what does a single long task cost the user?

level: middleimportance: must knowfreq 70%

answer

  1. one thread does everything visible
  2. a task runs to completion
  3. the response budget is about 100 ms
  4. half of that budget, in milliseconds
  5. single task over 50 ms

basics

~20 s

A long task is one uninterrupted unit of main-thread work lasting over 50 ms. The 50 ms comes from the roughly 100 ms budget for responding to input: it leaves half that budget free. While a long task runs, input, timers and frames all wait.

solid answer

~50 s

A browser tab does almost everything visual on one thread, and it processes work as discrete tasks — evaluating a script, running a timer callback, dispatching a click, handling a response. Tasks run to completion, so nothing preempts them. The Long Tasks API calls any single task over 50 ms a long task. The threshold comes from the response budget: users expect visible feedback within about 100 ms of an input, and input can land the instant a task starts, so capping tasks at 50 ms leaves roughly 50 ms to run the handler and paint. It is not a frame budget. The cost of one long task is that everything queues behind it: a 300 ms task on a 60 Hz display means about eighteen frames are never produced, clicks made during it are dispatched late, and that added latency is exactly what responsiveness metrics like INP measure. Crucially, ten 30 ms tasks total the same work but yield ten chances to respond.

go deeper

for a junior

Be able to say plainly that a browser page runs its JavaScript, styling and painting on one thread, and that a function which runs for a long time stops clicks and animation until it returns.

for a middle

Expect to give the definition precisely — one task over 50 ms, not aggregate scripting time — and to explain the 50 ms as headroom inside the roughly 100 ms input-response budget rather than as a frame time.

for a senior

Interviewers want you to connect a long task to what a real user reported: dead clicks, a stalled spinner, added input latency. Be ready to name likely sources at load and at interaction time and say which you would attack first.

for a principal

Own the framing that long tasks are a proxy, not a goal. Be ready to argue when chunking work merely hides the count, when the honest fix is shipping less code, and how you would set expectations for main-thread cost across teams.

## One thread, one queue A browser tab does nearly all of its visible work on a single thread — the main thread. It parses HTML, runs your JavaScript, recalculates styles, performs layout, paints, and dispatches events. The browser feeds that thread a queue of **tasks**: evaluating a `<script>`, running a `setTimeout` callback, delivering a network response to its handler, dispatching a click. A task runs to completion — nothing preempts it partway through. Between tasks the browser can handle pending input and produce a frame; during one, it can do neither. ## The definition The Long Tasks API defines a long task as a **single task whose execution takes more than 50 ms**. Notice what that is not. It is not "the page spent three seconds in scripting" — that is an aggregate. It is not a slow network request; downloads happen off the main thread and only their handlers run on it. It is one uninterrupted block of work that held the thread for over 50 ms. The distinction matters practically. Ten consecutive 30 ms tasks add up to 300 ms of CPU work and produce zero long tasks — and, more importantly, they give the browser ten openings to dispatch a click or paint a frame. One 300 ms task gives it none. ## Why 50 ms and not 16 ms The number is derived from the response budget popularised by Google's RAIL guidance: a user should get visible feedback within roughly 100 ms of an interaction, or the interface stops feeling instantaneous. Input can arrive at any moment, including immediately after a task begins. If every task finishes within 50 ms, then in the worst case the browser starts processing that input 50 ms late and still has about 50 ms left to run the handler and paint a response inside the 100 ms budget. So 50 ms is deliberately *half the response budget* — headroom for the interaction itself. It is not one animation frame (about 16.7 ms at 60 Hz); a task can sit well under the long-task threshold and still cost you frames. ## What one long task actually costs While it runs, everything waits: - queued input events are not dispatched, so clicks and keystrokes feel ignored; - timer and promise callbacks do not run; - the next frame is not produced, so animation and scroll-linked effects stall; - the browser's own style, layout and paint work cannot proceed. Concretely, a frame at 60 Hz is about 16.7 ms, so a 300 ms task means roughly eighteen frames that never happen — the screen holds its last painted image and the page reads as frozen. Any input that arrived during the task also pays the remaining wait as extra latency before its handler even starts, which is precisely the delay that responsiveness metrics such as INP capture. ## Where long tasks come from At load time: evaluating and compiling a large JavaScript bundle, framework bootstrap or hydration of server-rendered markup, parsing a large embedded JSON payload, and third-party tag initialisation. At interaction time: sorting or transforming a large array, building thousands of DOM nodes in one go, expensive synchronous work inside an event handler, a large synchronous serialization, or drawing a complex canvas scene. ## Seeing them In a performance trace, long tasks show up as blocks over 50 ms on the main-thread track. Page audits aggregate them into Total Blocking Time. In the field a `PerformanceObserver` can report them directly: ```js new PerformanceObserver((list) => { for (const entry of list.getEntries()) { console.log('long task', entry.duration); } }).observe({ type: 'longtask', buffered: true }); ``` ## The three moves — and one trap There are only three real answers: do less work, do it later, or do it somewhere else. Ship and execute less JavaScript at that moment; postpone work the user does not need yet; move pure computation off the main thread. The trap is treating the count as the goal. Splitting a 300 ms task into seven 45 ms tasks drives the long-task count to zero while the user still waits roughly 300 ms for their frame. The browser does gain six chances to interleave input, which is real, but the count is a proxy — the user's wait is the thing being measured.

  • If a page has 300 ms of total scripting time, does that mean it has long tasks?
    Not necessarily. Long tasks are about the shape of the work, not the total. Ten 30 ms tasks spend the same 300 ms but leave ten gaps where the browser can dispatch input and paint. One 300 ms task spends it with no gaps at all. Total scripting time tells you how much CPU the page needs; long tasks tell you whether the user could interact while it ran.
  • Does a long task block the network requests a page has already started?
    No — the transfers themselves proceed off the main thread, so bytes keep arriving. What blocks is everything that needs the main thread afterwards: the response handler, promise resolution, and any DOM update built from the data. Requests that would be discovered by JavaScript which has not run yet are a different story: they cannot even start until the thread frees up.
  • Is a long task always a bug?
    No. Some work genuinely costs that much — an initial bundle has to be evaluated, a large dataset parsed once. What makes it a defect is when it overlaps a moment the user is trying to interact, or when it repeats. A 400 ms task while a splash screen is showing and nothing is clickable matters far less than a 120 ms task on every keystroke.

saying these in an interview costs you the question

  • Says a long task is anything taking over one second
  • Thinks total scripting time and long tasks are the same measure
  • Believes wrapping slow code in a Promise or async stops it blocking
  • Confuses a slow network request with a long task
  • Assumes long tasks only matter during initial page load

context

open as a page

Total Blocking Time (TBT) is reported for a page load. How is it computed from the page's long tasks, and why can a page with one 900 ms task score far worse than a page with six 120 ms tasks?

level: middleimportance: should knowfreq 52%

basics

~20 s

Total Blocking Time sums, over every long task in the measured load window, the amount by which that task exceeds 50 ms. One 900 ms task contributes 850 ms; six 120 ms tasks contribute 70 ms each, or 420 ms. Anything at or under 50 ms contributes nothing.

open as a page

A server-rendered page shows its content in about a second, but clicks and taps do nothing for another two seconds. The trace shows one roughly 1.8 s main-thread task starting right after the JavaScript bundle finishes downloading. What is usually happening, and what are your options?

level: seniorimportance: should knowfreq 46%

basics

~20 s

That gap between visible and usable is the classic hydration cost: the server HTML paints, then one long task compiles and evaluates the bundle and attaches behaviour to the existing markup, blocking input until it finishes. The fixes shrink or split that work; making the download faster does not help.

open as a page

A team proposes moving the app's data layer — parsing and transforming large API responses — into a Web Worker to eliminate long tasks on the main thread. How would you evaluate that proposal?

level: principalimportance: should knowfreq 34%

basics

~20 s

Offloading pays off only when the work is pure computation and the data is cheap to move. Copying large objects across the boundary is itself main-thread work at both ends and can erase the win. Measure the real tasks, prototype the hot path, and price the complexity before committing.

open as a page

A page registers a PerformanceObserver for entryType 'longtask' and receives a 320 ms entry. How much does that entry actually tell you about which code was responsible, and what does the Long Animation Frames API ('long-animation-frame') add?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

A longtask entry gives duration, start time and a frame-level attribution — never the script or function responsible. The Long Animation Frames API reports whole slow frames instead of single tasks, with a per-script breakdown including source URL and function name, which is what makes field attribution usable.

open as a page