Оптимізація First Input Delay (FID) / Interaction to Next Paint (INP) сайту

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Оптимізація First Input Delay (FID) / Interaction to Next Paint (INP) сайту
Складна
~2-3 робочих дні
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Оптимізація FID та INP (відзивчивість інтерфейсу)

FID (First Input Delay) замінений на INP (Interaction to Next Paint) у березні 2024. INP — строгіша метрика: вимірює всі взаємодії протягом сеансу, а не тільки першу. Мета INP: ≤ 200 мс.

Як працює INP

INP = час від дії користувача (mousedown, keydown, pointerdown) до наступного рендеринга фрейма браузером.

Затримка складається з:

  1. Input delay — очікування поки main thread звільниться від поточної задачі
  2. Processing time — час виконання обробників подій
  3. Presentation delay — час до фактичного рендеринга (layout, paint, composite)

Діагностика повільних взаємодій

// Моніторинг усіх взаємодій
new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
        if (entry.duration > 200) {
            console.warn(`Slow interaction: ${entry.name}`, {
                duration:          entry.duration,
                processingStart:   entry.processingStart,
                processingEnd:     entry.processingEnd,
                inputDelay:        entry.processingStart - entry.startTime,
                processingTime:    entry.processingEnd - entry.processingStart,
                presentationDelay: entry.startTime + entry.duration - entry.processingEnd,
            });
        }
    }
}).observe({ type: 'event', buffered: true, durationThreshold: 16 });

Chrome DevTools → Performance → запис сторінки → фільтр Long Tasks (червона смуга). Будь-яка задача > 50 мс — кандидат на оптимізацію.

Усунення Long Tasks

Розбивка синхронних обчислень:

// До: блокує main thread на сотні мс
function filterProducts(products, filters) {
    return products.filter(p => matchesFilters(p, filters));
}

// Після: yield кожні 50 елементів
async function filterProductsAsync(products, filters) {
    const results = [];
    for (let i = 0; i < products.length; i++) {
        if (matchesFilters(products[i], filters)) {
            results.push(products[i]);
        }
        if (i % 50 === 0 && i > 0) {
            await scheduler.yield(); // Chrome 115+
            // fallback: await new Promise(r => setTimeout(r, 0));
        }
    }
    return results;
}

Web Worker для CPU-інтенсивних задач:

// worker.js
self.onmessage = function({ data: { products, filters } }) {
    const results = products.filter(p => matchesFilters(p, filters));
    self.postMessage(results);
};

// main.js
const worker = new Worker('/js/filter-worker.js');
worker.postMessage({ products, filters });
worker.onmessage = ({ data }) => setFilteredProducts(data);

Оптимізація React-компонентів

Проблема: надмірне перерендеринг на кожний keystroke:

// Погано: синхронна фільтрація на кожний keystroke
function ProductList() {
    const [query, setQuery] = useState('');
    const filtered = products.filter(p =>
        p.name.toLowerCase().includes(query.toLowerCase())
    );

    return <>
        <input onChange={e => setQuery(e.target.value)} />
        <ul>{filtered.map(p => <ProductItem key={p.id} product={p} />)}</ul>
    </>;
}

// Добре: поле введення терміне, список відкладено
function ProductList() {
    const [query, setQuery] = useState('');
    const [deferredQuery, setDeferredQuery] = useState('');

    const filtered = useMemo(
        () => products.filter(p => p.name.toLowerCase().includes(deferredQuery.toLowerCase())),
        [deferredQuery]
    );

    function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
        const value = e.target.value;
        setQuery(value); // терміне — поле реагує миттєво
        startTransition(() => {
            setDeferredQuery(value); // некритичне — список оновиться пізніше
        });
    }

    return <>
        <input value={query} onChange={handleChange} />
        <ul>{filtered.map(p => <ProductItem key={p.id} product={p} />)}</ul>
    </>;
}

Віртуалізація довгих списків:

import { useVirtualizer } from '@tanstack/react-virtual';

function VirtualProductList({ products }: { products: Product[] }) {
    const parentRef = useRef<HTMLDivElement>(null);
    const rowVirtualizer = useVirtualizer({
        count: products.length,
        getScrollElement: () => parentRef.current,
        estimateSize: () => 80,
        overscan: 5,
    });

    return (
        <div ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>
            <div style={{ height: rowVirtualizer.getTotalSize() }}>
                {rowVirtualizer.getVirtualItems().map(virtualRow => (
                    <div key={virtualRow.index}
                         style={{ transform: `translateY(${virtualRow.start}px)`, position: 'absolute', width: '100%' }}>
                        <ProductItem product={products[virtualRow.index]} />
                    </div>
                ))}
            </div>
        </div>
    );
}

Оптимізація обробників подій

// Throttle для scroll/resize обробників
const handleScroll = throttle(() => {
    updateStickyHeader();
}, 16); // ~60fps

window.addEventListener('scroll', handleScroll, { passive: true });

// passive: true — повідомляє браузеру, що обробник не викличе preventDefault
// Дозволяє браузеру прокручуватися без очікування JS

Third-party скрипти

Чати, пікселі, аналітика — розповсюджена причина поганого INP. Вони виконуються в main thread та блокують взаємодії.

<!-- Завантаження після основного контенту -->
<script>
window.addEventListener('load', () => {
    setTimeout(() => {
        // Ініціалізація чату/піксела
        loadChatWidget();
    }, 3000); // затримка 3 секунди після load
});
</script>

Альтернатива — Partytown (Astro/Next.js): запускає third-party скрипти в Web Worker, повністю звільняючи main thread.

Цілі INP

Тип взаємодії Мета
Клік по кнопці < 100 мс
Введення в поле пошуку < 150 мс
Відкриття модального вікна < 200 мс
Фільтрація каталогу < 200 мс

Час оптимізації: 3–7 днів залежно від кількості проблемних взаємодій.