2 min read

Background Tasks API

The Background Tasks API provides the requestIdleCallback() method, which allows developers to queue functions to be executed during a browser's idle periods. This enables you to perform low-priority background work (like sending analytics or pre-loading data) without impacting latency-critical events such as animation and input response.

1. The Concept

The main thread is often busy handling user interactions and rendering. If you run a heavy task, the UI freezes. requestIdleCallback asks the browser: "Call me back when you aren't doing anything important."

2. Basic Usage

To schedule a task, pass a callback function to requestIdleCallback().

function myBackgroundTask(deadline) {
  console.log("Running in background...");
  // Do work...
}

const handle = requestIdleCallback(myBackgroundTask);

3. The deadline Object

The callback function receives a deadline object with two properties:

  • timeRemaining(): A function that returns the number of milliseconds remaining in the current idle period.
  • didTimeout: A boolean indicating if the callback is running because the timeout (if specified) was reached.
function processData(deadline) {
  while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && tasks.length > 0) {
    doWork(tasks.pop());
  }

  // If there are still tasks left, schedule another callback
  if (tasks.length > 0) {
    requestIdleCallback(processData);
  }
}

4. The timeout Option

You can specify a timeout in the options object. If the browser is too busy and the idle callback hasn't been called by this time, the browser will force it to run (even if it causes jank).

requestIdleCallback(processData, { timeout: 2000 });

5. Canceling a Task

You can cancel a scheduled task using cancelIdleCallback().

const handle = requestIdleCallback(myBackgroundTask);

// Later...
cancelIdleCallback(handle);

6. Fallback

Not all browsers support this API (notably Safari for a long time). A simple polyfill uses setTimeout.

window.requestIdleCallback = window.requestIdleCallback || function(cb) {
  return setTimeout(() => {
    cb({ didTimeout: false, timeRemaining: () => 1 });
  }, 1);
};

programming/javascript/vanilla/javascript programming/javascript/vanilla/event-loop