Оптимізація кількості HTTP-запитів 1С-Бітрікс
На аудиті Бітрікс-проєктів регулярно зустрічається сторінка з 180–250 HTTP-запитами при завантаженні. Це не перебільшення: кожен компонент може додати 2–4 CSS-файли та 3–5 JS-файлів, плюс іконки як окремі PNG, плюс трекери аналітики, плюс віджети. Кожен запит — це DNS, TCP, TLS, заголовки відповіді. При HTTP/1.1 браузер тримає 6 паралельних з'єднань на домен. При HTTP/2 мультиплексування допомагає, але не усуває накладні витрати повністю.
Аудит поточного стану
Перший крок — виміряти, а не вгадувати. Інструменти:
- Chrome DevTools → Network: колонки Requests, Transferred, DOMContentLoaded, Load
- WebPageTest (webpagetest.org): Waterfall-діаграма з групуванням за типами
- Lighthouse: метрика «Serve static assets with an efficient cache policy» + «Avoid chaining critical requests»
Дивимось на водоспаді: де найдовші ланцюжки залежностей? Зазвичай картина така:
HTML → CSS (×5) → шрифти (×6) → JS (×8) → зображення (×40+) → Ajax-запити компонентів (×3-5)
CSS та JS: комбайнер і бандлінг
Вбудований комбайнер Бітрікс
У налаштуваннях головного модуля (/bitrix/admin/settings.php?lang=ru) є «Об'єднувати CSS-файли» та «Об'єднувати JS-файли». Комбайнер об'єднує файли в один запит /bitrix/cache/css/[hash].css. Він працює, але є нюанси:
- Об'єднує лише файли з
AddCSS()/AddHeadScript(), але не inline-стилі компонентів - При інвалідації кешу (правка будь-якого файлу) hash змінюється — браузери завантажують заново
- Не мінімізує CSS/JS — лише конкатенація
Webpack/Vite для кастомних ресурсів
Для власного коду (не ядра Бітрікс) налаштовуємо бандлер:
// vite.config.js
export default {
build: {
rollupOptions: {
input: {
main: 'local/templates/main/src/main.js',
catalog: 'local/templates/main/src/catalog.js',
}
}
}
}
Отримуємо 2 бандли замість 15+ окремих файлів. Розділення на main і catalog важливе: не вантажимо JS каталогу на статичних сторінках.
Іконки: спрайти та inline SVG
Кожна іконка як окремий файл — найшвидший спосіб отримати 30–50 зайвих запитів. Варіанти:
SVG-спрайт — один файл з усіма іконками:
<!-- sprite.svg -->
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="icon-cart" viewBox="0 0 24 24">...</symbol>
<symbol id="icon-search" viewBox="0 0 24 24">...</symbol>
</svg>
<!-- використання -->
<svg><use href="/local/templates/main/img/sprite.svg#icon-cart"></use></svg>
Один HTTP-запит для всієї іконографії сайту. Кешується надовго.
Inline SVG через PHP-хелпер для іконок першого екрана:
function svg(string $name): string {
static $cache = [];
if (!isset($cache[$name])) {
$path = __DIR__ . '/icons/' . $name . '.svg';
$cache[$name] = file_exists($path) ? file_get_contents($path) : '';
}
return $cache[$name];
}
Inline SVG = 0 HTTP-запитів, але збільшує розмір HTML.
Ajax-запити компонентів
Бітрікс-компоненти з 'AJAX_MODE' => 'Y' роблять окремий XHR при переході між сторінками каталогу. Це нормально, але при ініціалізації сторінки часто видно кілька паралельних Ajax-запитів до ajax.php з різними параметрами. Рішення — batching: об'єднати кілька запитів в один через чергу:
// Накопичуємо запити за 50 мс, потім відправляємо batch
const queue = [];
function batchRequest(params) {
queue.push(params);
if (queue.length === 1) {
setTimeout(() => {
const batch = [...queue];
queue.length = 0;
fetch('/api/batch', {
method: 'POST',
body: JSON.stringify(batch)
});
}, 50);
}
}
На стороні сервера — endpoint /api/batch, який диспетчеризує запити і повертає масив відповідей.
Зображення: lazy loading і спрайти
Зображення в каталозі — найбільше джерело запитів. Обов'язковий мінімум:
// У шаблоні компонента catalog.element
echo '<img src="' . $arItem['PREVIEW_PICTURE']['SRC'] . '"
loading="lazy"
width="' . $arItem['PREVIEW_PICTURE']['WIDTH'] . '"
height="' . $arItem['PREVIEW_PICTURE']['HEIGHT'] . '"
alt="' . htmlspecialchars($arItem['NAME']) . '">';
loading="lazy" — нативний lazy loading. Браузер не запитує зображення нижче viewport до прокручування. На сторінці каталогу з 48 картками це прибирає 30–40 запитів із критичного шляху.
Кейс: оптимізація маркетплейсу
Онлайн-магазин електроніки на Бітрікс «Електронна торгівля»: головна сторінка — 214 HTTP-запитів, Load time 8,3 с.
Що зробили покроково:
- Увімкнули CSS/JS комбайнер → -18 запитів
- Зібрали SVG-спрайт із 64 іконок → -63 запити
- Додали
loading="lazy"всім зображенням нижче fold → -41 запит із критичного шляху - Перенесли Google Analytics та Яндекс.Метрику на
defer→ прибрали з блокуючого шляху - Об'єднали 5 кастомних JS-файлів через Vite в 1 бандл → -4 запити
Підсумок: 214 → 88 запитів, Load time: 8,3 с → 3,1 с, LCP: 5,2 с → 1,9 с.
HTTP/2 Push і preload
При HTTP/2 можна анонсувати ресурси через Link: <url>; rel=preload у заголовку відповіді. У Nginx:
location = / {
add_header Link "</local/templates/main/fonts/roboto-400.woff2>; rel=preload; as=font; crossorigin";
add_header Link "</local/templates/main/css/main.css>; rel=preload; as=style";
}
Це не зменшує кількість запитів, але скорочує водоспад — браузер дізнається про ресурси раніше.
Терміни
| Масштаб | Склад | Термін |
|---|---|---|
| Базовий | Комбайнер, lazy loading, defer трекерів | 1–2 дні |
| Середній | SVG-спрайт, Vite-бандлінг кастомного коду, HTTP/2 | 4–7 днів |
| Повний | Batch API для Ajax, повний аудит і усунення всіх надлишкових запитів | 8–14 днів |







