requestIdleCallback(callback, { timeout }) runs low-priority work, such as analytics, when the main thread is idle, so input and animation stay smooth. The callback receives an IdleDeadline: timeRemaining() gives the milliseconds left in the idle period (at most 50), and didTimeout is true when timeout forced the call.
let left = 200;
let periods = 0;
function work(deadline) {
periods++;
while (left > 0 && (deadline.timeRemaining() > 0 || deadline.didTimeout)) {
left--;
for (const end = performance.now() + 2; performance.now() < end;); // 2 ms of fake work
}
if (left > 0) requestIdleCallback(work, { timeout: 1000 });
else console.log(`200 tasks done in ${periods} idle periods`);
}
requestIdleCallback(work, { timeout: 1000 });Output
200 tasks done in 10 idle periods
requestIdleCallback() is not Baseline because Safari 10 lacks it, so feature-detect and fall back to setTimeout(). To split urgent long tasks, use scheduler.yield() (Chrome 129 1 , Firefox 142 555 , not Safari).