How the Long Tasks API Reports Main-Thread Blocking
The Long Tasks API provides JavaScript developers with a standardized
way to detect and measure operations that monopolize the browser’s main
UI thread for extended periods. Because JavaScript is single-threaded,
any execution that runs for more than 50 milliseconds can delay user
interactions, cause frame drops, and degrade perceived performance. This
article explains how the Long Tasks API identifies these blocking
operations, how to implement it using PerformanceObserver,
and the specific diagnostic data it surfaces to help optimize web
applications.
What Constitutes a Long Task?
In modern web performance standards, any continuous execution block on the main thread exceeding 50 milliseconds is classified as a long task. The 50ms threshold is derived from the RAIL performance model, which aims to ensure the browser responds to user inputs within 100ms. A 50ms buffer allows the browser to process queued tasks and still handle immediate user input smoothly.
When an operation exceeds 50ms, the Long Tasks API automatically captures it as a performance entry and flags it for monitoring.
How the API Collects and Reports Data
The Long Tasks API utilizes the PerformanceObserver
interface to monitor and report execution times asynchronously without
adding overhead to the critical rendering path.
Implementation Example
To observe long tasks, instantiate a PerformanceObserver
registered with the longtask entry type:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`Long Task Detected:`);
console.log(`- Start Time: ${entry.startTime.toFixed(2)}ms`);
console.log(`- Duration: ${entry.duration.toFixed(2)}ms`);
// Inspect attribution details
entry.attribution.forEach((attribution) => {
console.log(`- Source: ${attribution.name}`);
console.log(`- Container Type: ${attribution.containerType}`);
console.log(`- Container ID: ${attribution.containerId}`);
console.log(`- Container Name: ${attribution.containerName}`);
console.log(`- Container Source: ${attribution.containerSrc}`);
});
}
});
// Start observing long task entries
observer.observe({ entryTypes: ['longtask'] });Key Properties in Long Task Entries
Each reported event returns a PerformanceLongTaskTiming
object containing vital diagnostic metrics:
duration: The total elapsed execution time in milliseconds. Because it is a long task, this value is always greater than50.startTime: A high-resolution timestamp marking the beginning of the execution relative to the page’s time origin.name: Describes the origin of the execution relative to the browsing context. Common values include:self: The task originated within the current top-level frame.same-origin-ancestor,same-origin-descendant, orsame-origin: The task originated in a same-origin iframe.cross-origin-ancestororcross-origin-descendant: The task originated in a cross-origin iframe.unknown: The source cannot be determined due to cross-origin security restrictions.
attribution: An array ofTaskAttributionTimingobjects providing deeper context regarding the source element or container (e.g., specific<iframe>elements or embeds) responsible for the work.
Practical Use Cases
Reporting main-thread blocking operations via the Long Tasks API helps developers:
- Improve Core Web Vitals: Directly analyze Total Blocking Time (TBT) and Interaction to Next Paint (INP) bottlenecks.
- Audit Third-Party Scripts: Identify rogue third-party widgets, analytics tags, or ad scripts that delay page interactivity.
- Optimize Framework Overhead: Pinpoint expensive re-renders, complex DOM calculations, or unoptimized hydration phases in modern Single Page Applications (SPAs).