Оптимізація FID (First Input Delay) для 1С-Bitrix
FID (First Input Delay) — час від першої взаємодії користувача зі сторінкою до моменту, коли браузер почав обробляти цю взаємодію. З березня 2024 року Google замінив FID на INP (Interaction to Next Paint), який вимірює всі взаємодії, а не лише першу. На практиці оптимізація однакова для обох метрик.
Поріг: FID < 100 мс, INP < 200 мс. На важких Bitrix-сайтах INP може досягати 500–1500 мс.
Чому браузер не реагує на клік
Браузер однопоточний: поки головний потік занятий виконанням JavaScript, він не може обробляти події введення. Користувач натискає кнопку — клік ставиться в чергу і чекає, поки JS завершить поточне завдання.
Джерела довгих завдань (Long Tasks, > 50 мс) у Bitrix:
- Завантаження та розбір великих JS-бандлів: jQuery + плагіни + компоненти = 500 КБ — 1 МБ
- Ініціалізація слайдерів, масок-полів, карт, віджетів при
DOMContentLoaded - Важкі обробники подій: фільтр каталогу, перерахунок кошика
- Синхронні AJAX-запити (блокують потік)
Діагностика Long Tasks
Chrome DevTools → Performance → запис при завантаженні сторінки. Червоні смуги над Tasks — це Long Tasks > 50 мс. Клацніть на завдання — DevTools покаже стек викликів: який скрипт займав головний потік.
Для INP: DevTools → Performance → увімкніть «Web Vitals» → взаємодійте зі сторінкою → знайдіть INP-події.
Моніторинг консолі:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 50) {
console.warn('Long task:', entry.duration.toFixed(1) + 'ms', entry);
}
}
});
observer.observe({ type: 'longtask', buffered: true });
Розбивка бандла та code splitting
Стандартний Bitrix завантажує весь JS на кожній сторінці: jQuery, плагіни каталогу, скрипти кошика, слайдери, карти — все одразу. Сторінка з 1 МБ JS виконує його повністю при завантаженні.
Перехід на code splitting: кожен компонент завантажує лише необхідні скрипти:
// Завантажувати слайдер лише якщо на сторінці є слайдер
if (document.querySelector('.main-slider')) {
import('./swiper.min.js').then(({ default: Swiper }) => {
new Swiper('.main-slider', { /* ... */ });
});
}
// Карта лише на сторінці контактів
if (document.querySelector('#map')) {
import('./ymaps-init.js');
}
У контексті Bitrix — через \Bitrix\Main\Page\Asset::addJs() у конкретних шаблонах компонентів, а не у header.php.
Defer та async для скриптів
<!-- Синхронний — блокує розбір HTML -->
<script src="/bitrix/js/plugin.js"></script>
<!-- defer — завантажується паралельно, виконується після розбору HTML -->
<script src="/bitrix/js/plugin.js" defer></script>
<!-- async — завантажується та виконується якомога раніше -->
<script src="/bitrix/js/analytics.js" async></script>
defer — для скриптів, яким потрібен DOM (ініціалізація компонентів).
async — для незалежних скриптів (аналітика, рекламні теги).
У Bitrix JS-файли, додані через \Bitrix\Main\Page\Asset::addJs(), виводяться без defer. Для додавання атрибута — користувацька реалізація через хук OnEndBufferContent або переопределення шаблону виведення скриптів.
Важкі обробники подій
Обробник клику, який робить синхронний перерахунок DOM на 200 елементів, блокує потік на час цього перерахунку. INP буде дорівнювати часу обробника.
Паттерни поліпшення:
Debounce для частих подій (введення в пошуку, зміна фільтра):
let debounceTimer;
searchInput.addEventListener('input', function() {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
doSearch(this.value);
}, 300);
});
Розбивка важких операцій через setTimeout / scheduler.postTask:
async function processLargeList(items) {
for (let i = 0; i < items.length; i += 50) {
const chunk = items.slice(i, i + 50);
processChunk(chunk);
// Уступити управління браузеру між пакетами
await new Promise(resolve => setTimeout(resolve, 0));
}
}
Web Workers для обчислень: якщо в обробнику подій потрібні важкі обчислення (сортування, фільтрація великого масиву даних) — винесіть у Web Worker. Працює в окремому потоці, не блокує UI.
Сторонні скрипти
JivoSite, MetrikaTag, Google Analytics, піксель соцмереж — кожен додає JS, який виконується в головному потоці. При 5–10 сторонніх скриптах сумарне навантаження на старт може складати 200–500 мс Long Tasks.
Стратегія:
- Завантажувати сторонні скрипти через
asyncабо післяload-події - Використовувати
requestIdleCallbackдля некритичних скриптів - Перевірити, потрібні ли всі підключені віджети — часто залишаються невикористані
// Завантажити аналітику після idle
window.addEventListener('load', () => {
requestIdleCallback(() => {
const script = document.createElement('script');
script.src = 'https://analytics-provider.com/tag.js';
script.async = true;
document.head.appendChild(script);
});
});
Терміни оптимізації
| Завдання | Термін | Ефект |
|---|---|---|
| Аудит Long Tasks через DevTools | 0.5 дня | Розуміння проблеми |
| Переведення скриптів на defer | 1 день | INP −50–200 мс |
| Відкладення сторонніх скриптів | 0.5 дня | INP −100–300 мс |
| Debounce на пошук і фільтри | 1 день | INP фільтра −200–500 мс |
| Code splitting для важких компонентів | 3–5 днів | INP на сторінках каталогу −200–500 мс |
| Рефакторинг важких обробників подій | 2–5 днів | INP < 200 мс |
Хорошим результатом для Bitrix-магазину вважається INP < 200 мс. Це досягається при сумарному бандлі JS < 200 КБ (after parse) і відсутності Long Tasks > 100 мс при взаємодії.







