Drain deferred work one item per idle period

Performancekamo-marketing
Shipped
August 20, 2026 at 10:18 PM UTC
Author
Kamo
Commit
4c123b2

Four components waited for the main thread to go quiet before doing their work — the toast/consent bundle, the scroll chrome, the touch target sweep and the referral beacon — and each called requestIdleCallback itself. Each was right on its own and wrong together: the browser does not hand out an idle period per caller, it drains every pending callback in the same one. Measured on the homepage at 4x CPU throttle, the four fired at 2,359 / 2,361 / 2,413 / 2,444 ms. That 85 ms cluster is the long task the report attributed to the router chunk at ~2.4 s. They now go through a shared queue that runs one job per idle period and yields to the event loop in between. The total work is identical; it arrives as several short tasks instead of one long one, which is what Total Blocking Time actually counts — only the part of a task past 50 ms is blocking, so four 20 ms tasks cost nothing where one 80 ms task costs 30 ms. onIdle returns a canceller so the two call sites with real teardown semantics keep them: the beacon must not report a page the reader has already left, and the touch sweep must not run after unmount. check-idle-queue.mjs fails the build on a direct requestIdleCallback outside the queue, because the next person to defer something will reach for it and it will look correct in review.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing