Hurtigere hjemmeside hjælp til en langsom hjemmeside

Brug Transfer-Encoding

Lær at finde ud af om din server eller reverse proxy buffer HTML-svar, og få streaming (chunked) til at flytte første visning og LCP i den rigtige retning.

Skrevet af Kim Tetzlaff

Trin-for-trin

  1. Mål baseline: TTFB samt FCP/LCP (og hvilket element der er LCP) i Lighthouse eller WebPageTest.

  2. Tjek dokument-responsen i DevTools for `Transfer-Encoding: chunked` (og fravær af `Content-Length`).

  3. Verificér at HTML faktisk streamer i praksis (ikke kun i headers).

  4. Fjern buffering i det sted du har kontrol: app/framework og/eller reverse proxy-lag.

  5. Genmål: se om det flytter både FCP og (det vigtigste) element render delay / LCP.

Målet

At få siden til at starte tidligere ved at undgå unødvendig buffering. Når HTML kan blive sendt i bidder via Transfer-Encoding, får browseren ofte flere muligheder for at komme i gang med parsing, styling og senere paint.

Det kan forbedre både oplevet hastighed og LCP, men kun hvis streamet indhold faktisk hjælper din første visning (hero/H1/primary content) og ikke stoppes af render-blocking.

Før du går i gang

  • Hav en baseline klar: TTFB, FCP og LCP (og helst LCP-elementet) fra mindst 3 kørsler.
  • Tjek om problemet er stabilt: hvis det svinger meget, kan der være en cache- eller upstream-variant.
  • Du skal have en realistisk mulighed for at ændre noget i din stack:
    • app/framework output buffering
    • reverse proxy buffering for HTML
    • evt. komprimeringspipeline

Trin-for-trin

Trin 1: Afklar om det giver mening at jagte streaming

Start med at sammenligne:

  • TTFB (dokument-requestens første byte)
  • FCP/LCP (hvornår browseren faktisk viser noget / LCP-elementet bliver tegnet)
  • render delay (om elementet renderes sent)

Hvis du ser at HTML først ankommer “sent”, eller hvis TTFB er høj, kan buffering være årsagen. Hvis TTFB er lav, men LCP stadig er sent, kan det være ren render delay (typisk CSS/JS/paint/main-thread), og chunked alene er ikke løsningen.

Trin 2: Bekræft at dokumentet bruger Transfer-Encoding (chunked)

I Chrome DevTools:

  1. Åbn Network.
  2. Vælg document (din side-HTML).
  3. Kig i Response Headers:
    • skal du ofte se Transfer-Encoding: chunked (eller tegn på streaming uden Content-Length)
    • hvis du altid ser fuld Content-Length, kan du stadig streame, men chunked er den mest tydelige indikator

Vigtigt: At headeren findes i praksis er ikke det samme som at der reelt sker “progressiv” levering.

Trin 3: Bevis at HTML faktisk streamer undervejs

Den mest almindelige fejl jeg ser er: headers siger “chunked”, men svaret bliver stadig samlet i et bufferingslag, og browseren får intet før alt er klar.

Sådan verificerer du det:

  • Lav en test med cache slået fra og gerne en “langsommere” profil (fx DevTools throttling) for at få et tydeligt timing-mønster.
  • Åbn dokument-requesten og se om:
    • TTFB kommer tidligere end før
    • Content Download-delen ikke først “færdiggøres” ved samme tid som FCP/LCP
  • Hvis du kan, så brug DevTools Performance og kig efter om main-thread/painting starter tidligere, når du ændrer buffering.

Du leder efter et mønster hvor browseren får værdifuldt HTML tidligere, ikke bare at transporten er “chunked på papiret”.

Trin 4: Fjern buffering dér hvor den opstår

Buffering sker typisk i én af disse kroge:

  1. App/framework: output buffering (fx at JSON/HTML holdes tilbage indtil template er færdig)
  2. Reverse proxy/CDN: response buffering eller “send after complete”
  3. Komprimering: nogle pipelines buffer før gzip/brotli

Hvad du gør:

  • Gør det muligt at flushe tidligt i appen (grundidé: send de første “kritiske” stykker HTML tidligt).
  • Tilpas reverse proxy så den ikke bufferer HTML-responsen (ofte er der en “disable response buffering” mulighed for HTML).
  • Undgå at introducér for mange små bidder. Chunked handler om gradvis levering, ikke om at fragmentere alt ned til mikro-chunks.

Trin 5: Genmål og knyt det til LCP (ikke kun netværk)

Når du har ændret buffering:

  1. Kør Lighthouse/WebPageTest igen og sammenlign TTFB og FCP/LCP.
  2. Bekræft at det flytter den del af kæden der betyder noget:
    • enten tidligere parsing/discovery (FCP/element starter tidligere)
    • eller mindre render delay
  3. Tjek render-blocking først, hvis LCP stadig dominerer af paint/main-thread.

Typiske fejl

  • “Chunked headeren findes, men ingen effekt”: output er stadig buffered i app/proxy, eller første chunk indeholder ikke dit LCP-element.
  • Du løser TTFB, men LCP flytter sig ikke: din sidetype kan være render-blocking eller have tung paint. I så fald: fjern render-blocking eller adressér main thread.
  • Små bidder giver mere CPU: hvis du flush’er for ofte, kan du ende med dyrere total compute. Genmåling er obligatorisk.
  • Kædes forstyrres af caching: nogle proxy/CDN opsætninger ændrer caching adfærd på streaming-responser. Verificér repeat view.

Sådan kontrollerer du resultatet

  • TTFB: falder den på samme URL i samme testprofil?
  • FCP: kommer den tidligere end baseline?
  • LCP-element: bliver “element render delay” mindre, eller er det stadig et paint-problem?
  • Stabilitet: fungerer det på mobil og med ændringer slået til/af?

Praktisk checkliste

  • Transfer-Encoding/streaming er tydeligt i dokument-responsen
  • HTML streamer i praksis (ikke kun i headers)
  • LCP-elementet får kritisk HTML tidligere
  • Ingen nye render-blocking problemer blev introduceret
  • Repeat view og fielddata (hvis muligt) følger med

Relateret

Relaterede guides

FAQ

Kan chunked skade performance?

Ja. For aggressive flushes kan give mange små bidder (overhead), og nogle pipelines kan buffer i komprimering/caching-lag. Derfor skal du altid genmåle.

Hjælper chunked når render-blocking CSS/JS allerede dominerer?

Ofte ikke nok. Chunked kan gøre HTML tilgængelig tidligere, men hvis browseren ikke kan male (fx pga. CSS/JS i head), flytter LCP sig ikke. I så fald skal du først adressere [render-blocking](/ordbog/render-blocking/).

Skal jeg slå chunked “til” i min server manuelt?

Som udgangspunkt nej. På mange stacks er chunked en konsekvens af streaming og manglende `Content-Length`. Fokusér i stedet på at sikre tidlig flush og at proxy-lag ikke bufferer.

Næste skridt efter guiden

Brug emnesider, ordbog og blog til at validere og uddybe næste ændring.

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