requestIdleCallback asks the browser to run a callback when it considers the page idle. deadline.timeRemaining() estimates remaining time; it does not preempt JavaScript. The W3C draft defines callback scheduling and the deadline interface.

Conceptual illustration of a clock, a sleeping cat, and colored blocks along a horizontal line

An abstract timeline metaphor, not an actual browser schedule, deadline value, or API execution result.

Reserve it for deferrable work

Consider it for small pieces of noncritical work, such as preparing analytics or refreshing a cache, when doing the work must not delay input or rendering. Do not depend on it for animation, immediate interaction, or a write that must complete. Without a timeout, a callback can be postponed for an unbounded time if the browser does not provide idle periods.

Treat the deadline as an estimate

The callback’s didTimeout indicates whether it ran through the timeout route. timeRemaining() estimates how much of the current idle opportunity remains; it is not a preemptive execution limit. A long loop or synchronous function can still block the main thread. Check the estimate between bounded chunks and keep each chunk small.

A timeout does not promise completion

options.timeout requests an alternate queued execution if an idle period has not run the callback first. The browser may still delay its start because of scheduling and timer precision. In the timeout route, didTimeout is true and timeRemaining() may be zero. Do not interpret that as permission to drain an unbounded queue; impose a separate work limit.

Cancel stale work and check support

The request returns an identifier that can be passed to cancelIdleCallback to cancel a callback that has not run. Cancel obsolete work when page state makes it unnecessary. Check API support and behavior in target browsers. For work that must always progress, use an execution path with the needed guarantees rather than making idle callbacks the only route.

Apply it with bounded chunks

Suppose a page incrementally indexes items that are outside the viewport. Process a small bounded batch in each callback instead of scanning everything at once, and continue only while the estimate leaves room. Even when didTimeout is true, the callback can process one batch and schedule the remainder for another task. The browser chooses the idle budget; input size alone is not a reliable runtime estimate, so bound each synchronous step too.

If user input makes the work obsolete, cancel the returned handle. A rescheduling loop must track completion and failure in application state. timeout is neither a guaranteed callback start time nor a completion deadline for a chain of callbacks. If work must finish before a particular render or save, give it an explicit execution path instead of depending on the idle queue.

Keep progress state across callbacks

Keep the work cursor and completion/failure state in application state rather than only inside a callback closure. A later callback can then resume the work or discard it if it has become stale, even when scheduling is delayed or a callback is cancelled.

Sources