Frontend Development 14 min read

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.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Deep Dive into requestIdleCallback API and Its Use with React

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.

PerformanceJavaScriptreactWeb APIIdle TasksrequestIdleCallback
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.