Skip to main content

Функція requestIdleCallback()

requestIdleCallback(callback, [options]) реєструє колбек, який виконається тоді, коли браузер не зайнятий відмальовуванням чи обробкою подій, тобто у простої («idle time»). Це спосіб робити фонову роботу, не крадучи час у рендера й не підвішуючи інтерфейс.

Теорія

TL;DR

  • requestIdleCallback(fn) ставить fn у чергу idle-колбеків з найнижчим пріоритетом.
  • Колбек отримує об'єкт deadline з timeRemaining() і didTimeout.
  • Викликається у «вікні простою» між кадрами, коли рендер і мікротаски вже завершені.
  • { timeout: N } гарантує виклик не пізніше ніж через N мс, навіть якщо простою не було.
  • Повертає числовий ID, скасовується через cancelIdleCallback(id).
  • Не для критичних задач: на навантаженій або прихованій вкладці виклик може відкластися надовго.

Швидкий приклад

javascript
requestIdleCallback((deadline) => { while (deadline.timeRemaining() > 0) { console.log('Doing a background task'); } console.log('The browser is busy again, waiting for the next idle window'); });

Тут:

  • deadline, це спеціальний об'єкт, який передається в колбек;
  • deadline.timeRemaining() показує, скільки мілісекунд лишилося «вільними» до наступного кадру;
  • ви робите роботу, поки є час, а якщо не встигли, браузер викличе колбек знову в наступному вікні простою.

Що таке простій і як працює виклик

Браузер малює кадри приблизно 60 разів на секунду, тобто кожні 16.6 мс. Якщо якийсь кадр зайняв лише, скажімо, 10 мс, у браузера залишається приблизно 6 мс вільного часу, і саме туди може потрапити ваш requestIdleCallback. Так виконуються незначні або фонові задачі, некритичні до часу, без гальмування інтерфейсу.

Крок за кроком:

  1. Ви викликаєте requestIdleCallback(fn).
  2. Браузер додає fn у чергу задач idle callbacks.
  3. Коли Event Loop, відмальовування й мікротаски завершені, а до наступного кадру ще є час, браузер викликає ваш колбек.
  4. Якщо вкладка неактивна або вільного часу немає, колбек може відкладатися.

Аргументи: deadline і timeout

javascript
requestIdleCallback(callback, { timeout: 2000 });
  • callback(deadline), функція, яка отримає об'єкт:
    • deadline.timeRemaining(), скільки мілісекунд лишилося «до зайнятості»;
    • deadline.didTimeout, true, якщо вичерпався таймаут і колбек викликали «примусово».
  • options.timeout, максимальний час очікування. Якщо вільного моменту так і не з'явилося, колбек усе одно виконається через задану кількість мілісекунд.

Перевірка didTimeout дає змогу розрізнити два режими: у справжньому простої можна спокійно працювати, поки timeRemaining() > 0, а при вимушеному виклику timeRemaining() зазвичай дорівнює нулю, і варто зробити лише мінімум найнеобхіднішого.

Розбиття важкої роботи на частини

javascript
const tasks = Array.from({ length: 10000 }, (_, i) => i); function processTasks(deadline) { while (deadline.timeRemaining() > 0 && tasks.length > 0) { const task = tasks.shift(); // do a portion of the work console.log('Task processed', task); } if (tasks.length > 0) { requestIdleCallback(processTasks); } } requestIdleCallback(processTasks);

Такий підхід дозволяє обробити тисячі елементів без лагів: UI лишається чутливим, бо робота виконується в паузах між кадрами. Ключова деталь, це повторна реєстрація колбека, доки черга не спорожніє: одного виклику майже ніколи не вистачає.

Порівняння з setTimeout і requestAnimationFrame

КритерійsetTimeoutrequestAnimationFramerequestIdleCallback
МетаВиконати через N мсВиконати перед перемальовуванням кадруВиконати в паузі між кадрами
ПріоритетСереднійВисокий (для анімацій)Низький (фонові задачі)
Залежить від навантаженняНіТак, синхронізується з кадромТак, викликається лише коли браузер вільний
При неактивній вкладціМоже тротлитисяПризупиняєтьсяМоже затриматися надовго
ВикористанняТаймери, затримкиАнімації, плавні оновленняЛегкі фонові обчислення, кеш, логіка довантаження

Підтримка браузерами і фолбек

requestIdleCallback є не в усіх браузерах, зокрема його немає в Safari, тому краще мати фолбек:

javascript
const ric = window.requestIdleCallback || function (cb) { return setTimeout(() => cb({ timeRemaining: () => 0, didTimeout: true }), 1); };

Його не можна використовувати для критичних задач, бо він може не викликатися довго, якщо вкладка навантажена.

Підсумок:

ВластивістьЗначення
Що робитьВикликає колбек, коли в браузера є вільний час
Передає об'єктdeadline з timeRemaining() і didTimeout
Коли виконуєтьсяУ вікнах простою між кадрами
Використовується дляФонових задач, кешування, довантаження даних
Скасовується черезcancelIdleCallback(id)
ПовертаєЧисловий ID, як у таймерів

Типові помилки

  • Покладатися на нього для критичної логіки. Колбек може не виконатися хвилинами, якщо сторінка постійно зайнята. Для гарантії ставте timeout.
  • Ігнорувати timeRemaining(). Цикл без перевірки залишку часу з'їдає кадр і повертає ті самі лаги, від яких ви тікали.
  • Не перереєстровувати колбек. Одне вікно простою рідко вміщає всю роботу, тому в кінці треба знову викликати requestIdleCallback, якщо черга не порожня.
  • Малювати з нього. Зміни DOM усередині idle-колбека відбуваються після кадру і спричиняють зайвий reflow. Для візуальних оновлень є requestAnimationFrame.
  • Забувати про відсутність підтримки. Без фолбека код просто нічого не робить у Safari, і баг довго лишається непоміченим.
  • Не скасовувати запланований колбек. Після зникнення компонента виклик лишається в черзі, тому потрібен cancelIdleCallback(id).

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.