Lesson 29 of 30
Diagnosing a bad INP tells you where the time went. This lesson is the toolkit for actually closing the gap once you know.
13 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
A click handler processes a large array synchronously in one block before updating the UI. Breaking that work into chunks and yielding between them with `scheduler.yield()` (or a `setTimeout` fallback) — what does this actually change?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
This track's earlier INP-diagnosis lesson covered splitting a slow interaction into Input Delay, Processing Time, and Presentation Delay. The long-tasks lesson covered how to spot a long task occupying the main thread. Put together: once you know which part of an interaction is slow and what is occupying the thread when it shouldn't be, three concrete patterns are what actually close that gap.
Yield between chunks of work. A handler that does a large amount of synchronous work — say, processing a big array and updating state from it — runs as one uninterruptible block by default: nothing else, including the browser's own paint, can happen until it finishes. Breaking that work into smaller chunks and yielding to the main thread between them lets the browser paint or handle other input in the gaps, instead of the whole thing running as one long task.
Defer genuinely non-urgent work. Not everything triggered by an interaction needs to happen before the visible UI updates. An analytics call, a non-visual side effect, a background sync — none of these need to block the frame the user is waiting to see. Running the visible update first and pushing the non-urgent work to after it keeps the interaction itself fast.
Mark low-priority updates as low-priority. Some frameworks expose an API (conceptually similar to React's startTransition) that lets you tell the renderer "this state update can wait" so that urgent updates, like the visible feedback for the keystroke or click that just happened, aren't stuck behind it in the same render pass.
// Blocks the main thread for the whole loop — no paint can happen until it's done.
function handleFilterChange(items, query) {
const results = items.filter((item) => matches(item, query)); // expensive over a big list
renderResults(results);
}
// Yields between chunks so the browser can paint (and handle other input) in the gaps.
async function handleFilterChangeChunked(items, query) {
const results = [];
const CHUNK = 500;
for (let i = 0; i < items.length; i += CHUNK) {
const chunk = items.slice(i, i + CHUNK);
results.push(...chunk.filter((item) => matches(item, query)));
// scheduler.yield() where available; setTimeout(fn, 0) as the fallback for
// browsers that don't yet support it.
if ("scheduler" in window && "yield" in window.scheduler) {
await window.scheduler.yield();
} else {
await new Promise((resolve) => setTimeout(resolve, 0));
}
}
renderResults(results);
// Genuinely non-urgent — runs after the visible update, not before or blocking it.
logFilterUsage(query);
}
A handler runs as one long, uninterruptible block. Nothing else -- including a pending paint -- can happen until it finishes.
The chunked version does the exact same total amount of work. The difference is that it hands control back to the browser between chunks, so a paint the user is waiting on (or another input event) gets a chance to happen instead of queueing up behind the entire filter operation.
startTransition-style APIs mark updates as low-priority, not the whole handler. The urgent part (the input reflecting what the user just typed) still needs to update immediately — only the more expensive downstream re-render gets deprioritized."You've diagnosed a bad INP down to a long-running click handler — what do you actually do about it?" is where this track's diagnosis lessons meet real engineering judgment: naming yielding, deferral, and priority-marking as concrete, applicable techniques (not just "make it faster") is what separates a candidate who's actually shipped this fix from one who's only read about the metric.