Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Interaction Latency Traces and Main-Thread Contention

Last updated: 4 Oct 20268 min read
tutorial
IntermediateBy AITrove Editorial

A click can feel late even when its handler is short. The browser may be finishing another task before the handler starts, or it may run the handler promptly and then spend time computing layout and presenting the next frame. Diagnose an interaction as three intervals: input delay, event-handler processing, and presentation delay. The boundaries are observable in a detailed performance trace, but a single metric alone does not identify the guilty function. Long tasks elsewhere on the main thread increase queueing; synchronous JavaScript inside the handler increases processing; expensive style, layout, paint, or heavy DOM work after the handler increases presentation delay. The fix follows the largest interval, not the most familiar optimization tip.

Working case

A reviewer taps Approve and sees the button change 310 milliseconds later. A developer shortens a 14-millisecond handler but the interaction remains slow. A trace shows 190 milliseconds waiting behind a bulk filter operation, 14 milliseconds in the handler, and 106 milliseconds preparing the next frame. The approval request itself is asynchronous and does not account for the local delay. The team splits the filter work into bounded units, gives the approval button an immediate state change, and reduces a large summary panel update. They then repeat the trace under a slow CPU profile and while the filter runs, because an idle desktop trace had hidden the contention.

Implementation boundary

javascript
function interactionBudget(inputDelayMs, handlerMs, presentationMs, limitMs) {
  const totalMs = inputDelayMs + handlerMs + presentationMs;
  return { totalMs, withinBudget: totalMs <= limitMs };
}
console.log(JSON.stringify(interactionBudget(190, 14, 106, 240)));
// Output: {"totalMs":310,"withinBudget":false}

Capture a representative slow interaction with its preceding main-thread tasks, handler stack, and next visual frame. Label the user action and route. First identify the largest interval. If input delay dominates, remove unnecessary recurring work or divide work into chunks that permit input to run. If processing dominates, measure expensive synchronous parsing, validation, and loops inside the handler; move nonessential work after feedback or into a worker when the data-transfer cost is acceptable. If presentation dominates, inspect style recalculation, layout, DOM size, and paint work caused by the state change. A handler that schedules microtasks repeatedly may still hold the thread before a frame can render; yielding needs a real opportunity for rendering, not merely another promise callback. Keep optimistic UI tied to a clear rollback contract when a server mutation later fails.

Cost and boundaries

More scheduled chunks increase coordination overhead and may lengthen total compute time even as the page becomes responsive. Worker handoff copies or transfers data and adds cancellation and ownership rules. Immediate feedback can improve perceived response, but an incorrect optimistic result has an error-recovery cost. Measure both the worst user interaction and throughput of the background operation. Record trace conditions: device, CPU setting, data size, competing task, and visible state. A percentile without the route and interaction name can hide a small but important approval path. Avoid treating a synthetic idle trace as proof that field input delay is solved.

Failure trace

Run a 190-millisecond unrelated task immediately before the approval click; the handler may still measure 14 milliseconds while the user waits. Replace that task with many chained microtasks and verify a frame can actually render after the proposed yield. Force a server rejection after immediate approval feedback and confirm the button and audit state return to an accurate condition. Apply the same trace on a large case list and a short one; a fix that only works on the short list is incomplete. Disable a worker mid-computation and check cancellation, stale result handling, and cleanup.

Verification

  • The trace separates delay before handlers from work inside them.
  • A frame is allowed to render after a claimed yield.
  • Immediate feedback has a defined server-failure correction.

Practice drill

Take three traces of the Approve action: idle, while a 47,000-record filter runs, and during a summary-panel update. Annotate input delay, handler duration, and presentation delay for each. Keep the network request out of the local paint calculation. Choose one intervention for each dominant interval and predict its cost. Re-run with a modest CPU profile and with keyboard activation, since a click-only improvement may leave another input path slow. Record whether visible confirmation occurs before or after server commit and what the failure view says.

Decision note

Change the interval that consumes the time; a shorter handler does not cure queueing or slow paint.

Common Mistakes

  • Optimizing handler code while input delay dominates.
  • Assuming a resolved promise gives the browser a paint opportunity.
  • Reporting only an idle desktop interaction trace.

Related lessons

Browser Performance Diagnosis and Measurement; Field Performance Observation and Sample Contracts; Retained DOM Memory and Lifecycle Investigation; Layout, Paint Regressions, and Containment Decisions; Event Loop Tasks, Microtasks, and Paint; Cooperative Main-Thread Scheduling.

Apply and check

Build Project: permit browser regression investigation and review Web Development: browser performance diagnosis quiz.

web-tech
web-development
Storage details