What Are Long Tasks? Complete Guide (2026)

Saar Twito9 min read
Saar Twito
Saar TwitoFounder & SEO Engineer

Hi, I'm Saar - a software engineer, SEO specialist, and lecturer who loves building tools and teaching tech.

View author profile →

What Is a Long Task?

A long task is any single, uninterrupted piece of work on the browser's main thread that runs for more than 50 milliseconds. While a long task is running, the page cannot respond to clicks, taps, or key presses, and no new frames can paint. Long tasks are the primitive that produces bad Total Blocking Time (TBT) and slow Interaction to Next Paint (INP) — the latter being a Core Web Vital and a confirmed Google ranking signal.

Key Facts (TL;DR)

  • Definition: Any main-thread task > 50 ms is a long task, per the W3C Long Tasks API.
  • Goal: Zero long tasks during load and interaction. The 50 ms ceiling is the budget — not the target.
  • Very long task: > 100 ms — visibly perceptible to users.
  • Rage-click territory: > 200 ms — users frequently click again, queueing duplicate actions.
  • TBT formula: TBT is the sum of (task_duration − 50ms) for every long task between FCP and TTI. Good TBT is ≤ 200 ms.
  • INP impact: A single long task during an interaction (click, tap, keypress) can blow past INP's 200 ms "good" threshold and fail the Core Web Vital.
  • Where the 50 ms comes from: Google's RAIL model. Humans expect a response within ~100 ms; the browser needs ~50 ms of headroom for event dispatch and paint, leaving 50 ms of pure work as the upper bound.

Think of the main thread as a single-lane checkout. A 50 ms task is a customer with a basket; a 500 ms task is someone counting out coins. Everyone behind them — clicks, taps, animations — waits in the same line.

Why Long Tasks Cost You Conversions and Rankings

Long tasks cause the most viscerally bad parts of a slow site:

  • Dead clicks: A button is visible, but a long task is hogging the main thread when the user taps it. Nothing happens. They tap again. Now both clicks fire when the task ends — sometimes submitting the same form twice.
  • Janky scrolling and animation: A frame must paint every ~16 ms to hold 60 fps. A 100 ms task drops 6 frames in a row — a clearly visible stutter.
  • Failing INP, which is a ranking signal:INP became a Core Web Vital in March 2024. Pages that fail (75th-percentile interaction over 200 ms) lose ground in Google's Page Experience signal and tend to fall out of competitive results.
  • Lower AI search visibility: AI answer engines (Google AI Overviews, Perplexity, ChatGPT) preferentially cite pages that already rank well. Pages that fail INP — almost always due to long tasks — get cited less.
  • Bounce and rage: Industry analysis consistently links long tasks during interactions to higher bounce rates and lower conversion, especially on mobile, where CPUs are 4–6× slower than desktop.

How Long Tasks Are Measured (and Why 50 ms?)

The browser exposes long tasks through the Long Tasks API, which fires a PerformanceObserverentry for any task whose execution exceeds 50 ms. The 50 ms threshold is not arbitrary — it comes from Google's RAIL response-time model:

  • Humans perceive a response as "instant" only if it lands within roughly 100 ms.
  • The browser itself needs ~50 ms of headroom inside that window for event dispatch, hit testing, style recalc, and paint.
  • That leaves ~50 ms as the largest single chunk of pure work the main thread can do without making the user feel a delay.
// Detect long tasks in any browser that supports the API
if ('PerformanceObserver' in window) {
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      console.warn(
        `Long task: ${entry.duration.toFixed(0)}ms`,
        entry.name,
        entry.attribution
      );
    }
  });
  observer.observe({ type: 'longtask', buffered: true });
}

How Long Tasks Roll Up Into TBT

Total Blocking Time = Σ(task_duration − 50ms) for every long task between First Contentful Paint and Time to Interactive. A single 250 ms long task contributes 200 ms of TBT — instantly failing the "good" threshold by itself.

How Long Tasks Roll Up Into INP

INP measures the worst real-user input response across a session. The interaction's total duration is the sum of input delay, processing time, and presentation delay — and a long task in any of those phases lengthens INP. Fixing long tasks during clicks and keypresses is the single most effective INP fix.

How to Find Long Tasks on Your Site

  • Greadme deep scan — runs a full audit, lists every long task on the page, attributes them to specific scripts, and pairs each issue with an AI-generated fix or a one-click GitHub PR. Start at greadme.com/deep-scan.
  • Greadme crawler scan — scans every page on your site and flags templates whose long-task profile is dragging INP down.
  • Greadme AI visibility analyzer — checks whether your pages are surfacing in AI answer engines, which is closely correlated with passing Core Web Vitals (and therefore with not having long tasks during interactions).
  • Chrome DevTools → Performance tab — record an interaction; long tasks appear as red-tipped bars on the main-thread track. The flame chart shows exactly which function ran for how long.
  • Long Tasks API in production — wire a PerformanceObserver to your real-user monitoring so you can see long tasks on real devices, not just simulated ones.
  • Google Search Console → Core Web Vitals — surfaces pages failing INP at the 75th percentile, which is almost always a long-tasks problem.

8 Proven Ways to Eliminate Long Tasks

1. Yield to the Browser With scheduler.yield()

The native way to break up work in 2026. Inside a long loop or pipeline, awaiting scheduler.yield() hands control back to the browser — letting it process pending input and paint a frame — and resumes your work as the next task in the queue.

async function processItems(items) {
  for (const item of items) {
    doWork(item);

    // Yield so the browser can handle clicks and paint
    if ('scheduler' in window && 'yield' in scheduler) {
      await scheduler.yield();
    } else {
      await new Promise(r => setTimeout(r, 0));
    }
  }
}

2. Move CPU-Bound Work to a Web Worker

Anything that doesn't touch the DOM and runs longer than 50 ms — JSON parsing of large payloads, search/filter over big datasets, image manipulation, crypto — belongs on a worker thread. The main thread stays free to respond to input and paint frames.

// main.js
const worker = new Worker(
  new URL('./filter.worker.js', import.meta.url),
  { type: 'module' }
);

worker.postMessage({ query, dataset });
worker.onmessage = (e) => render(e.data);

3. Virtualize Large Lists

Rendering 5,000 rows is a guaranteed long task. List virtualization renders only the rows currently in the viewport (plus a small buffer), so the DOM stays small and updates stay fast. Most frameworks have a virtualization library — use one before you ship a long list.

4. Debounce and Throttle Frequent Events

Scroll, resize, and input events fire dozens of times per second. If their handler does anything non-trivial, you get cascading long tasks. Debounce handlers that should run after the user pauses (search-as-you-type with a 200 ms debounce) and throttle ones that should run periodically during continuous events (scroll-driven layout updates at 16 ms).

5. Defer Non-Critical Hydration

Full-page hydration on load is one of the most common sources of multi-hundred-millisecond long tasks. Move to islands or component-level hydration so only the genuinely interactive components run on the client, and so below-the-fold widgets hydrate on idle or on intersection.

6. Kill N+1 Patterns in Render Code

A render that reads from a Map 5,000 times, or recomputes the same selector inside a loop, can quietly create 100+ ms tasks. Memoize expensive selectors, hoist invariant work out of loops, and prefer batch updates over per-item reflows.

7. Use requestIdleCallback for Background Work

Logging, prefetching, analytics buffering, and other non-urgent work should run when the main thread has nothing else to do. requestIdleCallbackguarantees your work won't collide with a user interaction.

requestIdleCallback(() => {
  flushAnalyticsQueue();
  prefetchNextRoute();
}, { timeout: 2000 });

8. Keep Event Handlers Lean — Especially the Click Handler

The click handler is the hottest path in the app. Anything heavy inside it inflates INP directly. Update minimal state synchronously to give immediate feedback, then schedule the rest with scheduler.postTask, requestIdleCallback, or a worker.

Common Long-Task Issues and Fixes

Problem: Search/Filter Locks Up on Every Keystroke

What's happening: Each keystroke runs a synchronous filter over a 10,000-row dataset on the main thread.

Fix: Debounce the input (200–300 ms) and run the filter in a Web Worker. Render virtualized rows. Typical result: from 400 ms long tasks per keystroke to none.

Problem: Heavy First-Paint Hydration

What's happening: The framework hydrates the entire page on load, producing a single 600 ms long task that destroys INP for any click in the first few seconds.

Fix: Adopt islands/partial hydration. Mark static sections non-interactive. Hydrate below-the-fold components on intersection or idle.

Problem: Janky Infinite Scroll

What's happening: Every batch of new items inserts 50 DOM nodes synchronously, causing a long task and dropping frames.

Fix: Pre-fetch the next batch before the user reaches it, insert nodes in chunks of 5–10 with scheduler.yield() between chunks, or virtualize the list.

Problem: Rage Clicks on a "Submit" Button

What's happening: The form's submit handler runs synchronous validation over many fields, blocking the main thread for 250+ ms before the click visibly registers.

Fix: Show an immediate disabled/loading state synchronously, then move the validation pass off the main thread or into chunked work with scheduler.yield().

How Long Tasks Relate to TBT, INP, and Other Metrics

Long tasks are the underlying primitive. TBT, INP, and TTI are aggregations of long-task behavior across different windows.

MetricWhat It MeasuresGood ThresholdConnection to Long Tasks
Total Blocking Time (TBT)Sum of blocking time during load (lab metric)≤ 200 msTBT = Σ(task − 50 ms) for every long task between FCP and TTI.
Interaction to Next Paint (INP)Worst real-user input response (Core Web Vital)≤ 200 msINP is dominated by long tasks during input handling and rendering.
Time to Interactive (TTI)When the page can reliably respond to input≤ 3.8 sTTI fires after a 5-second window with no long tasks.
JavaScript Bootup TimeCPU time spent parsing, compiling, executing JS≤ 2 sBootup is the source of most load-time long tasks.
First Input Delay (FID)Delay before the first input is processed (deprecated 2024)≤ 100 msReplaced by INP. Both are dominated by long tasks.

FAQ

Why is the long-task threshold exactly 50 ms?

It comes from Google's RAIL model. Humans perceive a response as "instant" only within ~100 ms; the browser needs about 50 ms of that for event dispatch and paint, so any single chunk of pure work over 50 ms eats into the budget the user can feel.

Are long tasks a Google ranking factor?

Indirectly, yes. Long tasks themselves aren't a ranking factor, but they directly determine INP, which became a Core Web Vital in March 2024 and is a confirmed input to Google's Page Experience ranking signal. Eliminating long tasks during interactions is the most reliable way to pass INP.

What's the difference between TBT and Long Tasks?

Long tasks are the underlying events; TBT is an aggregation. Specifically, TBT is the sum of (task_duration − 50 ms) for every long task between FCP and TTI. A page can have one 300 ms long task (TBT contribution: 250 ms) or six 100 ms long tasks (TBT: 300 ms) — different shapes, similar pain.

Will Web Workers fix every long task?

Only the ones that don't touch the DOM. Workers are perfect for parsing large JSON, search/filter over big datasets, image processing, and cryptography. Anything that mutates the DOM (rendering, layout, hydration) has to stay on the main thread — for those, the fix is yielding (scheduler.yield()), virtualization, or shipping less work.

How do I monitor long tasks in production?

Use a PerformanceObserver with type 'longtask'to capture them on real devices, send the data to your real-user monitoring, and alert when the 75th percentile of long-task duration crosses 100 ms on any high-traffic page. Greadme's crawler scan also surfaces this data per template.

Do AI search engines like ChatGPT and Perplexity care about long tasks?

Indirectly. AI answer engines preferentially cite pages that already rank well in traditional search. Long tasks degrade INP, which degrades Page Experience, which lowers rankings — and lower-ranking pages get cited less in Google AI Overviews, Perplexity, and ChatGPT browsing results.

Is setTimeout(fn, 0) still a valid yielding pattern?

It works, but scheduler.yield() is preferred when available. setTimeout(0) goes to the back of the task queue, which means other tasks (including unrelated ones) can run before yours resumes. scheduler.yield() is designed to resume your work next, with a single browser turn in between for input and paint.

Conclusion

Long tasks are the atomic unit of a sluggish website. Every bad TBT score, every failed INP, every rage-click on a button that "didn't work" traces back to one. The good news: the fixes are concrete and well-understood — yield, offload, virtualize, debounce, and stop hydrating things that don't need it.

Run a Greadme deep scan to see exactly which long tasks are running on your pages, what scripts caused them, and the AI-generated fix or one-click GitHub PR to ship the change.