SquellSquell
Zpět na archiv
↗Performance9. května 2026·8 min čtení

INP pod 200 ms: scheduler.yield() v praxi (2026)

INP je dva roky Core Web Vital a stále padá většině e-shopů. Nový scheduler.yield() v Chrome 129+ je nejúčinnější fix — co reálně funguje.

AutorDavid Jurica
Diagram INP thresholdů: pod 200 ms good, 200–500 needs improvement, nad 500 poor
Foto: web.dev

Od 12. března 2024, kdy INP nahradil First Input Delay v sadě Core Web Vitals, uplynuly dva roky. Threshold zůstává: dobré skóre je 200 ms na 75. percentilu, mezi 200 a 500 ms je „needs improvement“, nad 500 ms poor. Co se ale změnilo, je tooling. Chrome 129 v září 2024 oficiálně dostal scheduler.yield() a v 2026 už je dostupný i ve stable Edge. Pro většinu pomalých interakcí v JS-heavy aplikacích je to nejjednodušší fix, který reálně hne čísly.

Co INP měří a proč padá

INP měří latenci od user inputu (klik, klávesa, tap) k vykreslení dalšího framu, který odráží odpověď. Bere nejhorší interakci na stránce za celou návštěvu, ne průměr. Důvod, proč padá u většiny CMS a e-shopových šablon:

  • ▸Long task — jakákoliv JS úloha nad 50 ms blokuje hlavní vlákno a posouvá next paint.
  • ▸Hydration React/Next.js komponent na velkých stránkách produkuje 300–800 ms tasky při interakci s nehydrated subtree.
  • ▸Třetí strany — analytics, A/B test SDK, chatboty — běhají na main threadu a queueují své vlastní tasky před vaše.
  • ▸DOM s 4000+ uzly způsobuje pomalý style/layout recalc i u triviálních změn.

„Long tasks delay the browser's ability to respond to user input, creating a perception that a site is slow. With scheduler.yield(), you can break up long tasks into smaller chunks, improving responsiveness by explicitly yielding back to the main thread.“

— Jeremy Wagner, web.dev

scheduler.yield() prakticky

Klasický pattern setTimeout(fn, 0) pro dělení tasku má jednu vadu: continuace skončí na konci queue, takže vás tam předběhnou taski třetích stran. scheduler.yield() vrací promise, jejíž continuace má prioritu — pokračujete dřív, než spustí cokoliv jiného.

  • ▸async function processItems(items) { for (const item of items) { doWork(item); if (needsYield()) await scheduler.yield(); } }
  • ▸Polyfill: const yieldToMain = () => 'scheduler' in window && 'yield' in scheduler ? scheduler.yield() : new Promise(r => setTimeout(r, 0));
  • ▸needsYield() typicky: performance.now() - taskStart > 50 nebo navigator.scheduling.isInputPending(). isInputPending vrací true, pokud uživatel klikl/píše a my drž blokujeme.

Kde to měřit

Lighthouse v lab prostředí INP nezachytí spolehlivě — je založen na simulovaných interakcích. Pravdivá data jsou v Chrome User Experience Report (CrUX) a v real-user monitoringu. Knihovna web-vitals na NPM přímo emituje INP eventy. Pro lokální debug Performance panel v DevTools má od Chrome 130 sekci Interactions, kde vidíte breakdown na input delay, processing time a presentation delay.

Praktická hranice: pokud v Performance panelu vidíte processing time přes 100 ms, to je váš problém. Input delay nad 50 ms znamená, že nějaký jiný task běžel, když uživatel klikl — typicky analytika nebo hydration.

Co dělat kromě yieldu

  • ▸Defer hydration u Next.js: použít React Server Components a hydrovat jen interaktivní islandy.
  • ▸Třetí strany izolovat do Web Workeru přes Partytown, kde to dává smysl (analytika typicky ano, A/B test ne).
  • ▸Virtualizovat dlouhé listy — tanstack-virtual sníží DOM uzly z 5000 na 50 a INP klesne i bez dalších úprav.
  • ▸content-visibility: auto na off-screen sekce, aby browser neflikoval style recalc.
  • ▸Optimistic UI updaty — vykreslit intermediate stav okamžitě a server response zpracovat asynchronně.

Co s tím

Pro nový projekt: měřit INP v real-user monitoringu od dne jedna, ne čekat na to, až Search Console začne zobrazovat červená čísla. U existujícího webu s INP nad 200 ms začít DevTools Performance Interactions panelem a najít tři nejhorší interakce. V devíti z deseti případů je řešením kombinace scheduler.yield() v custom kódu, deferred hydration a izolace třetích stran — ne refaktor frameworku. INP není o tom, jak rychle váš JS běží. Je o tom, jak často pustí uživatele ke slovu.