Deep Dive into requestIdleCallback API and Its Use with React
This article explains the requestIdleCallback web API, its syntax, execution timing, task‑queue handling, performance characteristics, compatibility issues, and practical integration with React and requestAnimationFrame to off‑load low‑priority work without blocking UI rendering.
In this article we explore the requestIdleCallback (rIC) API, an often‑overlooked browser feature that lets developers schedule background or low‑priority work during idle periods of the main event loop. Although the article is part of a React fundamentals series, the concepts apply to any front‑end code.
Syntax Introduction
The API is called as window.requestIdleCallback(callback[, options]) . It returns an ID ( handle ) that can be cancelled with Window.cancelIdleCallback(handle) . The callback receives an IdleDeadline object exposing didTimeout and timeRemaining() . The optional options currently only supports a timeout value.
var handle = window.requestIdleCallback(callback[, options])Basic Usage
A simple example logs the deadline object with a 1000 ms timeout:
requestIdleCallback((deadline) => {
console.log(deadline);
}, {timeout: 1000});The console output shows the returned ID (e.g., 14 ) and the didTimeout flag as well as the estimated remaining milliseconds via deadline.timeRemaining() .
When Does It Run?
After a frame finishes input handling, rendering, and compositing, the browser enters an idle period until the next frame starts, a new task is queued, or user input arrives. Idle periods are typically very short (under 16 ms on a 60 Hz display). If no screen refresh occurs, the browser creates consecutive 50 ms idle windows, limited to avoid perceptible input latency.
Execution Frequency
In practice, requestIdleCallback may be invoked about 20 times per second (once per 50 ms idle window). This low call rate is acceptable because each callback can process many queued tasks.
Task Queue Processing
Tasks are stored in an array ( taskList ) and processed while there is remaining idle time or the callback has timed out:
let taskHandle = null;
let taskList = [
() => { console.log('task1'); },
() => { console.log('task2'); },
() => { console.log('task3'); }
];
function runTaskQueue(deadline) {
console.log(`deadline: ${deadline.timeRemaining()}`);
while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && taskList.length) {
let task = taskList.shift();
task();
}
if (taskList.length) {
taskHandle = requestIdleCallback(runTaskQueue, { timeout: 1000 });
} else {
taskHandle = 0;
}
}
requestIdleCallback(runTaskQueue, { timeout: 1000 });If a task takes longer than the current idle slice, the browser automatically continues it in the next idle period.
Avoid Direct DOM Manipulation
Changing the DOM inside an idle callback can force a layout/repaint, negating the benefits of idle execution. Instead, schedule DOM updates with requestAnimationFrame after the idle work is done.
Combining with requestAnimationFrame
The article provides a React component that enqueues tasks via requestIdleCallback and triggers DOM updates with requestAnimationFrame . This pattern keeps heavy computation off the main rendering path while still updating the UI efficiently.
Performance Comparison
When a large synchronous task (e.g., logging 50 000–100 000 items) is executed directly, a loading animation stalls. The same workload performed via requestIdleCallback does not block the animation, demonstrating the API’s advantage for preserving UI responsiveness.
Compatibility and Polyfill
Browser support for requestIdleCallback is limited; a simple polyfill using setTimeout can approximate the API by limiting execution to 50 ms slices, though it cannot guarantee true idle‑time execution.
window.requestIdleCallback = window.requestIdleCallback || function(handler) {
let startTime = Date.now();
return setTimeout(function() {
handler({
didTimeout: false,
timeRemaining: function() {
return Math.max(0, 50.0 - (Date.now() - startTime));
}
});
}, 1);
};Relation to React
Early versions of React used requestIdleCallback for scheduling, but modern React no longer relies on it. The article treats the API as a general performance tool rather than a React‑specific feature.
React Series Overview
React createElement source analysis
Difference between elements and components
Refs and forwardRef source analysis
Context evolution and implementation
Race Condition handling
Suspense deep dive
From visual persistence to FPS, refresh rate, GPU, V‑sync, and the 16 ms story
requestAnimationFrame execution mechanism
The series aims to provide around 50 articles that dissect React APIs from a source‑code perspective.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.