The JavaScript engine
Long tasks block the page
Understand why a long JavaScript function delays input handlers, timers, style work, layout, and painting.
The main thread runs your JavaScript. It also runs most of the style calculation, layout, and paint work. And it can do only one thing at a time.
So while a JavaScript task runs, nothing else happens. No clicks are handled. No timers fire. No frame is painted.
Let’s make that visible:
button.addEventListener('click', () => {
const end = performance.now() + 500
while (performance.now() < end) {
// Simulate expensive synchronous work.
}
status.textContent = 'Done'
})
Click the button. The handler spins for half a second, then sets the text. But the visitor sees nothing change for those 500 ms. The DOM update is near the end of the handler, and the browser can’t paint until the task finishes and it gets a rendering opportunity.
Click twice quickly and the second click waits too. It’s queued as a task, and it runs only after the first one is done. This is why a page can look fully loaded and still feel frozen.
What counts as long
Performance tools flag any task longer than 50 milliseconds as a long task. The number comes from the RAIL model: if the browser needs about 50 ms to respond to input and paint a frame, a task longer than that makes the response feel late.
Treat 50 ms as a diagnostic line, not a budget. Five tasks of 40 ms in a row still make an interaction feel slow. Nothing gets flagged, and the page still feels bad.
Find the task, then pick the fix
Record the click in the Performance panel. Look for a wide block on the Main track. Expand it until you find the function that eats the time. The flame chart shows you the caller chain, so you know how you got there.
Then choose a fix that matches the work:
- remove calculations whose result nobody uses
- use a better algorithm or process less data
- split deferrable work into chunks and yield between them, so input and rendering can run
- move CPU-heavy work that doesn’t touch the DOM to a Web Worker
The order matters. Deleting work beats splitting it. Splitting has overhead, and a worker adds messaging and data-transfer cost.
Measure the interaction, not the function
After the change, record the same click again. The goal is not a shorter function. The goal is a faster next paint and a page that responds to the second click.
A function that went from 500 ms to 300 ms is still a long task. A function that yields every 30 ms, letting the browser paint in between, feels responsive even if the total work is the same.
Lesson completed