Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Функція requestIdleCallback()». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`requestIdleCallback(callback, [options])` реєструє колбек, який браузер викличе тоді, коли він не зайнятий відмальовуванням чи обробкою подій, тобто у «вікні простою» між кадрами.** Браузер малює кадр приблизно кожні 16.6 мс, і якщо кадр зайняв лише 10 мс, залишається близько 6 мс вільного часу, куди й потрапляє ваш колбек. У колбек передається об'єкт `deadline` з методом `timeRemaining()`, що показує залишок вільних мілісекунд, і прапорцем `didTimeout`. Опція `{ timeout: 2000 }` гарантує, що колбек виконається не пізніше ніж через задану кількість мілісекунд, навіть якщо простою так і не було. Виклик повертає числовий ID, який скасовується через `cancelIdleCallback(id)`. ```javascript requestIdleCallback((deadline) => { while (deadline.timeRemaining() > 0 && queue.length > 0) { process(queue.shift()); } }, { timeout: 2000 }); ``` **Ключове:** `requestIdleCallback()`, це низькопріоритетна черга для фонових задач, які не критичні до часу і не повинні гальмувати інтерфейс.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`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` | Критерій | `setTimeout` | `requestAnimationFrame` | `requestIdleCallback` | | --- | --- | --- | --- | | Мета | Виконати через 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)`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.