Hurtigere hjemmeside hjælp til en langsom hjemmeside

Event loop

Event loop er browserens køsystem for JavaScript, rendering og events. Når du forstår event loop, forstår du hvorfor klik kan føles langsomme, og hvorfor INP/long tasks opstår.

Skrevet af Kim Tetzlaff

Kort fortalt: Event loop er browserens måde at styre hvad der får lov at køre hvornår på main thread: JavaScript, events (klik, scroll), timers, netværkscallbacks – og rendering. Hvis event loop er fyldt af lange opgaver, føles siden tung, og metrics som INP bliver dårligere.

Hvad betyder event loop?

Forestil dig main thread som en “en-sporet vej”. Der kan kun køre én ting ad gangen:

  • en click handler
  • en stor DOM-opdatering
  • parsing/evaluering af scripts
  • layout/paint

Event loop er trafikpolitiet: den tager næste opgave fra en kø, kører den færdig, og går videre til næste. Problemet er: hvis en opgave varer længe, står resten i kø.

Hvorfor er det vigtigt for performance?

INP (respons på interaktion)

INP handler om hvor hurtigt en interaktion kommer frem til “næste paint”. Hvis event loop er optaget – fx af en lang JS-opgave – kan input ikke behandles i tide.

Det er derfor du kan have:

  • ok LCP/TTFB
  • men stadig en side der føles langsom at bruge

“Main thread work”

Når du ser “main-thread work” i Lighthouse/PSI, er det ofte et symptom på at event loop har for meget at lave: lange scripts, tung rendering, mange style/layout-kørsler eller tredjeparts der kører på dårlige tidspunkter.

Hvis du vil have bedre interaktionsoplevelse, er målet i praksis:

  • færre store opgaver på main thread
  • flere pauser hvor browseren kan nå at render’e
  • og mindre layout/paint-arbejde per interaktion

En enkel mental model (begynder-venlig)

Du kan tænke event loop som denne cyklus:

  1. Browseren tager én opgave (en “task”) fra køen.
  2. Den kører opgaven færdig.
  3. Den kører microtasks (ofte promises) der blev planlagt i opgaven.
  4. Når der er luft, forsøger den at render’e (style → layout → paint → composite).
  5. Den gentager.

Det er punkt 2–4 der typisk gør forskellen mellem “føles hurtigt” og “føles tungt”.

Tasks, microtasks og rendering (for øvede)

Tasks (macrotasks)

“Tasks” er fx:

  • click/keydown events
  • setTimeout
  • netværkscallbacks

De er tydelige “blokke” af arbejde.

Microtasks

Microtasks er ofte:

  • Promise.then(...)
  • async/await fortsættelser

De køres typisk lige efter en task, før browseren går videre. Det kan være godt (du får din logik færdig), men kan være skidt hvis du lægger meget arbejde i microtasks, fordi du kan “sulte” rendering – dvs. du holder browseren fra at nå næste paint.

Hvis du har oplevet at en UI-opdatering “kommer sent” selvom du gjorde det “async”, kan microtasks være en del af forklaringen.

Eksempel: Hvorfor async ikke automatisk gør det hurtigt

Et klassisk eksempel:

  • du splitter din kode op med await
  • men du laver stadig 200ms DOM-arbejde i én sammenhængende blok efter await’et

Resultat: event loop er stadig optaget, og input-respons lider.

Det hjælper ofte mere at:

  • reducere mængden af arbejde
  • chunk’e arbejde op (fx over flere frames)
  • og undgå layout-thrashing (se næste afsnit)

Typiske årsager til “blokering”

1) Store click handlers

Du klikker → handler gør:

  • databehandling
  • DOM-opbygning
  • målinger af DOM (getBoundingClientRect, offsetHeight, osv.)
  • opdatering af klasser/inline styles

Hvis alt det sker i én blok, kan du få dårlig INP og ofte også flere Long Tasks.

2) Layout thrashing (forced reflow)

Når du skifter mellem at læse layout (måle DOM) og skrive layout (ændre DOM/styles) i samme loop, kan browseren blive tvunget til at lave layout igen og igen.

Det er et af de mest almindelige “det føles langsomt” problemer i UI-kode. Se også opslaget om Layout thrashing.

3) Tredjeparts-scripts

Tredjepart kan:

  • køre på uheldige tidspunkter (på load eller ved klik)
  • binde mange event listeners
  • lave dyr DOM-manipulation

Se Third-party scripts hvis du vil have konkrete typiske syndere.

4) Dyr rendering/painters

Det er ikke altid JS. Store gradients, blur, fixed overlays og store repaints kan også gøre at event loop ikke kommer til “næste paint” hurtigt.

Det er en af grundene til at nogle sider har ok netværk, men stadig har stor “render delay” i LCP-opdelingen.

Sådan finder du problemet (praktisk)

  1. Optag en interaktion i Chrome DevTools Performance.
  2. Find det langsomme klik/scroll.
  3. Kig på hvor tiden går:
    • Scripting (JS)
    • Rendering (style/layout)
    • Painting (paint/composite)
  4. Identificér den største blok og start dér.

Hvis du vil forstå netværk/ressourcer samtidig, suppler med Waterfall-analyse.

Hvad du kan gøre (typiske greb)

  • Skær JS væk: mindre bundle, færre dependencies. Se JavaScript bundle og Tree shaking.
  • Udskyd tredjepart: load senere eller efter consent. Se Third-party scripts.
  • Undgå layout thrashing: batch DOM reads, batch DOM writes.
  • Gør rendering billigere: færre dyre effekter i kritisk path; brug isolering/containment hvor det giver mening (se content-visibility og contain).

Relaterede begreber

  • INP – metrikken du typisk jagter når event loop er flaskehals
  • Long Task – symptomer på lange JS-opgaver
  • Main thread – hvorfor alt kæmper om samme ressource
  • Hydration – når frameworks gør interaktion dyrere end forventet

FAQ

Hvorfor bliver et klik langsomt når 'CPU'en ikke er 100%'?

Fordi respons handler om main thread. Hvis event loop er optaget af en lang opgave (JS, layout, paint), kan input ikke behandles før køen er fri – selv hvis resten af maskinen har kapacitet.

Er promises og async/await altid hurtigere?

Nej. De ændrer hvordan arbejde planlægges (microtasks), men hvis du stadig laver meget arbejde samlet, kan du stadig blokere main thread og få dårlig INP.

Hvad er forskellen på tasks og microtasks?

Tasks er “normale” køpunkter (events, timers). Microtasks (promises) køres typisk lige efter en task og før rendering – hvilket kan være godt eller skidt afhængigt af hvor meget du lægger der.

Eksterne kilder

Event loop er en del af HTML-standarden og dokumenteres praktisk på MDN.

Næste skridt fra begreb til handling

Guides og blogindlæg der matcher begrebets emne - ud fra fælles tags og sidens fokus.

Om forfatteren

Kim Tetzlaff

Kim skriver og vedligeholder indhold på hurtigere-hjemmeside.dk med fokus på målelig performance, Core Web Vitals og teknisk SEO. Målet er at gøre optimering konkret: hvad der faktisk flytter tal i feltdata, og hvordan du finder den korteste vej fra symptom til fix.

Kim Tetzlaff