ESC

Type to search the knowledge base.

Long Tasks API

Detect main-thread tasks over 50ms with PerformanceObserver longtask entries and fix INP-killing work.

advanced3 min read
  • browser
  • long-tasks
  • performance
  • inp
  • main-thread

A long task is main-thread work that blocks the event loop for 50ms+. During that window the browser can’t run input handlers or paint — users feel dead UI. The Long Tasks API surfaces these as longtask performance entries.

Docs: Long Tasks API — MDN, web.dev long tasks, LoAF (newer).

Observe long tasks

const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('longtask', entry.duration, entry.attribution);
  }
});
po.observe({ type: 'longtask', buffered: true });

Support varies; in production many teams use this in Chromium browsers and accept partial coverage. Long Animation Frames (LoAF) is the richer successor for attributing scripting vs style/layout — track both as platform evolves.

Why 50ms

At 60Hz a frame is ~16.7ms. A 50ms+ block guarantees multiple missed frames and delayed input. INP budgets (good ≤ 200ms) get eaten quickly if a 120ms task sits in front of a click.

Typical sources

Source Example
JS parse/compile/eval Huge bundles on main
Synchronous work JSON.parse megabytes, tight loops
Framework render Re-rendering massive trees
Third parties Tags, chat widgets, A/B
Layout thrash Forced sync layout in loops

Breaking work up

async function processChunks(items) {
  const CHUNK = 32;
  for (let i = 0; i < items.length; i += CHUNK) {
    items.slice(i, i + CHUNK).forEach(doWork);
    // yield to event loop / prefer scheduler.yield when available
    await new Promise((r) => setTimeout(r, 0));
  }
}

Better: await scheduler.yield() — scheduler yield. Also requestIdleCallback for truly deferrable work (not input-critical).

Attribution limits

Classic longtask attribution is coarse (often “unknown” or script container). Combine with:

  1. Performance panel flame charts
  2. User Timing marks around suspects
  3. Field INP attribution (web-vitals)
  4. Removing third parties behind flags

TBT vs long tasks vs INP

Total Blocking Time (lab) sums long-task blocking near load. INP is field interaction latency. Long tasks hurt both but fixing load TBT doesn’t automatically fix a heavy checkout click.

Interview out-loud

“Long Tasks API flags main-thread work over 50ms that blocks input and paint. I observe longtask entries, break work into chunks with yielding, and verify with Performance panel and INP field data — not TBT alone.”

Pairing with profiling

Long task entries tell you that something blocked; the Performance panel tells you what. Use User Timing marks around major features so RUM can attribute custom measures even when longtask attribution is unknown. Delete noisy marks after the investigation.

Further depth

Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.

Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.

Further reading

Related guides