Long Tasks og LoAF — Hvad blokerer main thread
Long Tasks er JavaScript over 50ms. LoAF (Long Animation Frame) er den nyere standard der måler frames over 50ms inkl. rendering-tid. Begge er diagnostiske metrics for INP-problemer.
Main thread er single-threaded. Når JavaScript kører, venter alt andet — brugerinput, scroll, animationer. Tasks der tager over 50ms kategoriseres som Long Tasks og er den primære årsag til dårlig INP. Long Animation Frames (LoAF) er den nyere, mere præcise diagnose-standard der måler hele render-frames frem for kun JavaScript-eksekvering. At identificere og eliminere Long Tasks er den mest direkte vej til at forbedre INP og Total Blocking Time.
Long Tasks API
Long Tasks API rapporterer eksekvering over 50ms:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.warn(`Long Task: ${Math.round(entry.duration)}ms`);
console.log('Attribution:', entry.attribution);
}
});
observer.observe({ type: 'longtask', buffered: true });
entry.attribution angiver hvilken frame og script der forårsagede tasken — nyttigt til at identificere tredjeparts-scripts som synderen.
Long Animation Frames (LoAF)
LoAF er Chromiums nyere API der erstatter Long Tasks som primær INP-diagnostik. Det måler frames over 50ms og inkluderer:
- JavaScript-eksekvering
- Style-beregning og layout
- Paint og compositing
- Script-attribuering per frame
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Scripts der bidrog til denne frame
for (const script of entry.scripts) {
console.log(`Script: ${script.sourceURL}`);
console.log(`Invoker: ${script.invokerType}`); // 'event-listener', 'promise-resolve', etc.
console.log(`Duration: ${script.duration}ms`);
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
LoAF er tilgængeligt i Chrome 123+ og er det tool Google Chrome DevTools bruger internt til INP-attribuering.
Hvad skaber Long Tasks
Monolitisk JavaScript: Et 2 MB bundle der eksekveres i én opgave ved sideload. Løsning: code splitting og lazy loading.
Synchronous layout thrashing: JavaScript der alternerer mellem at læse og skrive DOM-properties tvinger browseren til at genberegne layout synkront i en loop:
// BAD — forced synchronous layout per iteration
elements.forEach(el => {
const height = el.offsetHeight; // Trigger layout
el.style.height = (height * 2) + 'px'; // Invalidate layout
});
// GOOD — batch reads, then batch writes
const heights = elements.map(el => el.offsetHeight); // Alle reads
elements.forEach((el, i) => {
el.style.height = (heights[i] * 2) + 'px'; // Alle writes
});
Tredjeparts-scripts: Analytics, A/B-test og chatscripts der kører tunge initialiseringsrutiner ved load.
Event handlers der gør for meget: En scroll- eller input-handler der beregner komplekse ting synkront.
Strategier til at eliminere Long Tasks
Task yielding — del lange tasks op i mindre chunks via scheduler.yield() (eller setTimeout(fn, 0) som fallback):
async function processItems(items) {
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
// Yield til main thread hvert 50. element
if (i % 50 === 0) {
await scheduler.yield(); // Chrome 115+
// Fallback: await new Promise(r => setTimeout(r, 0));
}
}
}
Web Workers — flyt tung beregning til worker thread helt.
requestIdleCallback — udskyd ikke-kritisk arbejde til browseren er idle:
requestIdleCallback((deadline) => {
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
tasks.shift()();
}
});
Måling i praksis
Chrome DevTools Performance-panel visualiserer Long Tasks som røde trekanter over task-blokke. Main track i timeline viser hvad der foregår — JavaScript-eksekvering, style-beregning, layout og paint.
Total Blocking Time (TBT) i Lighthouse aggregerer Long Task-tid — det er det lab-metric der bedst korrelerer med INP-field-data. → Denne artikel er en del af Web Performance — Core Web Vitals og teknisk hastighed.
Andre artikler i samme emne
- Animation performance — Frame rate og jank-fri bevægelse
- Billedoptimering — Formater, størrelser og SEO
- Browser rendering pipeline — Fra HTML til pixels
- CLS-problemer — Årsager til Cumulative Layout Shift og løsninger
- Core Web Vitals — LCP, INP og CLS forklaret
- CSS — Cascading Style Sheets og SEO
- CSS containment — Isolér rendering og accelerér layout
- Font-optimering — Webfonts, FOUT og SEO
- HTTP/2 og HTTP/3 — Protokoller der eliminerer latency-overhead
- INP-optimering — Interaction to Next Paint og Core Web Vitals
- JavaScript bundle-optimering — Code splitting, tree shaking og analyse
- Kritisk renderingsti — Hvad browseren gør før du ser noget
- Latency — Forsinkelse i netværket og hvad du kan gøre ved det
- Lazy loading — Udskyd indlæsning af billeder og ressourcer
- LCP-optimering — Sådan forbedrer du Largest Contentful Paint
- Navigation og resource timings — Browserens performance-API
- PageSpeed og SEO — Hastighed som rankingfaktor
- Performance budgets — Grænser der forhindrer regressioner
- Performance timings — Hvornår er det for langsomt?
- Resource hints — Preload, prefetch og preconnect til SEO
- Responsive images — srcset, sizes og art direction
- Responsivt design — Mobile-first og SEO
- RUM vs. syntetisk monitoring — To syn på web performance
- Service Workers — Offline caching og PWA performance
- Speculative loading — Prefetch og prerender af næste side
- Startup performance — Hurtig app-start og time to interactive
- Tredjeparts-scripts og performance — Impact og strategier
- Tredjepartsscripts — Analytics, ads og performance-konsekvenser
- TTFB og hosting — Server response time og SEO
- Video performance — Lazy loading, formater og indlæsningsstrategi
- Viewport tag — Meta viewport og mobil-rendering
- Web Workers — Parallel JavaScript uden main thread-blokning
Ofte stillede spørgsmål
- Hvad er en Long Task?
- En Long Task er enhver eksekvering på main thread der tager over 50 millisekunder. Under en Long Task kan browseren ikke processere brugerinput — klik, tastaturinput, scroll. Det er den primære mekanisme bag dårlig INP. Long Tasks rapporteres via PerformanceObserver med type 'longtask'.
- Hvad er forskellen på Long Tasks og Long Animation Frames (LoAF)?
- Long Tasks måler JavaScript-eksekvering over 50ms. LoAF (Long Animation Frames API) måler hele frames over 50ms inkl. JavaScript, style-beregning, layout og paint — ikke kun JavaScript. LoAF giver mere præcis attribuering til hvad der faktisk forårsager forsinkelsen, inkl. tredjeparts-scripts og rendering-overhead.
- Hvad er Total Blocking Time (TBT) og hvordan relaterer det til Long Tasks?
- TBT er Lighthouse-metrikken der summerer den tid Long Tasks blokerer main thread udover 50ms-grænsen — det vil sige: en 200ms Long Task bidrager med 150ms til TBT. TBT er et lab-metric der korrelerer stærkt med field-INP fordi begge er drevet af Long Tasks. Lighthouse rapporterer TBT og bruges til at estimere INP-forbedringspotentiale uden at afvente field data.
- Hvad er tredjeparts-scripts' rolle i Long Tasks og hvordan identificeres de?
- Tredjeparts-scripts — analytics, A/B-test, chat-widgets og ad-scripts — er en hyppig kilde til Long Tasks. De kører på main thread og kan blokere brugerinteraktion i hundredvis af millisekunder. Long Animation Frames API's entry.scripts[] giver specifik attribuering til hvilke scripts der forårsager lange frames, inkl. sourceURL og invokerType. I Chrome DevTools' Performance panel fremgår tredjeparts-scripts som separate frames i timeline — identificer dem ved domain-navn i call stacks.
- Hvad er task yielding og hvilke teknikker er tilgængelige?
- Task yielding er strategien at opdele lange synchronous tasks i kortere chunks der giver main thread tilbage til browseren imellem. Tilgængelige teknikker: scheduler.yield() (Chrome 115+, bedstemulighed — høj prioritet, designet til yielding), setTimeout(fn, 0) (bred support, lavere prioritet), requestIdleCallback (kører kun under idle, ukontrolleret prioritet). scheduler.yield() er den anbefalede løsning til kritisk kode der skal opdeles uden at miste høj interaktionsprioritet. For ikke-tidskritisk baggrundsarbejde er requestIdleCallback mere passende.
Placering i ordbogen
- Animation performance — Frame rate og jank-fri bevægelse
- Billedoptimering — Formater, størrelser og SEO
- Browser rendering pipeline — Fra HTML til pixels
- CLS-problemer — Årsager til Cumulative Layout Shift og løsninger
- Core Web Vitals — LCP, INP og CLS forklaret
- CSS — Cascading Style Sheets og SEO
- CSS containment — Isolér rendering og accelerér layout
- Font-optimering — Webfonts, FOUT og SEO
- HTTP/2 og HTTP/3 — Protokoller der eliminerer latency-overhead
- INP-optimering — Interaction to Next Paint og Core Web Vitals
- JavaScript bundle-optimering — Code splitting, tree shaking og analyse
- Kritisk renderingsti — Hvad browseren gør før du ser noget
- Latency — Forsinkelse i netværket og hvad du kan gøre ved det
- Lazy loading — Udskyd indlæsning af billeder og ressourcer
- LCP-optimering — Sådan forbedrer du Largest Contentful Paint
- Navigation og resource timings — Browserens performance-API
- PageSpeed og SEO — Hastighed som rankingfaktor
- Performance budgets — Grænser der forhindrer regressioner
- Performance timings — Hvornår er det for langsomt?
- Resource hints — Preload, prefetch og preconnect til SEO
- Responsive images — srcset, sizes og art direction
- Responsivt design — Mobile-first og SEO
- RUM vs. syntetisk monitoring — To syn på web performance
- Service Workers — Offline caching og PWA performance
- Speculative loading — Prefetch og prerender af næste side
- Startup performance — Hurtig app-start og time to interactive
- Tredjeparts-scripts og performance — Impact og strategier
- Tredjepartsscripts — Analytics, ads og performance-konsekvenser
- TTFB og hosting — Server response time og SEO
- Video performance — Lazy loading, formater og indlæsningsstrategi
- Viewport tag — Meta viewport og mobil-rendering
- Web Workers — Parallel JavaScript uden main thread-blokning