Browser & Frontend Runtime
Event loop: rescue an interaction from INP hell
Reading about long tasks is not the same as pulling an interaction out of one. Build a page with a deliberately janky interaction, measure its INP under realistic throttling, diagnose the offending frame with LoAF, and apply the unit’s yield discipline until input responds within one frame — with evidence at every step.
Turn the unit’s timing model into a reproducible engineering loop: reproduce a long task, attribute it from telemetry, chunk it under the 50 ms bar with a real task-level yield, defend the win with a CI gate, and verify with before/after INP numbers.
Take an interaction that blocks the main thread (your own app or the starter below) and bring its INP under 200 ms p75 on throttled hardware — without removing the feature — proving each step with measurements, not estimates.
- A before/after table: INP p75, longest main-thread task (ms), and dropped-frame count during a fixed typing sequence — all measured under 4x CPU throttling, not estimated.
- No single main-thread task exceeds 50 ms in the after trace; the LoAF stream no longer reports a slow frame for the interaction.
- INP p75 holds under 200 ms for the interaction at sustained typing speed.
- A one-paragraph write-up naming which yield primitive you used and why a microtask yield (await Promise.resolve()) would not have worked, referencing your trace.
- Add an INP CI gate: a Playwright test in headless Chrome with --cpu-throttling-rate=4 that replays the typing sequence, measures INP via the same PerformanceObserver code, and fails the build if p75 crosses the budget. Show it catches a regression you intentionally reintroduce.
- Add a starvation guard: write the classic Promise.resolve().then(self) freeze, observe zero frames painted and INP over 1 s in a trace, then break the cycle with one task-level yield and show the page recovers.
- Port the same heavy handler to a Node HTTP endpoint, measure event-loop lag with perf_hooks.monitorEventLoopDelay() under load, and show the Worker-thread fix drops p99 lag the same way the browser fix dropped INP.
- Wire the LoAF sourceCharPosition through a real sourcemap (source-map library or a Sentry-style resolver) so telemetry reports the original file:line, not the bundle position.
This is the loop you will run in every real INP incident: reproduce the long task under throttling, attribute the slow frame with LoAF plus a sourcemap, chunk the work under the 50 ms bar with a genuine task-level yield (never a microtask), push CPU-bound work to a Worker when chunking is not enough, and verify with before/after INP numbers under identical load. Gate it in CI with the same throttling so the win cannot silently regress. Doing it once on a toy page makes the production version muscle memory.