Service-Worker-Prefetch-Budget 2025 — Prioritätsregeln und gesundes INP

Veröffentlicht: 29. Sept. 2025 · Lesezeit: 5 Min. · Von Unified Image Tools Redaktion

Viele Teams führen Bild-Prefetching zur LCP-Verbesserung ein und stellen fest, dass der Service Worker die Leitung verstopft und das INP verschlechtert. 2025 verfügen wir über stabile Priority Hints und genauere Signale der Network Information API, wodurch sich Prefetch dynamisch steuern lässt. Dieser Artikel behandelt Zielassets und Timing als „Budget“ und zeigt, wie Hero-Bilder oder Galerien vorausgeladen werden, ohne die Nutzererfahrung zu schädigen.

TL;DR

  • Budget quantifizieren: budget = (Downlink × 0,25) - laufende LCP-Ressourcen; Prefetch pausieren, wenn das Ergebnis negativ wird.
  • Im Service Worker neu priorisieren: Navigation Timing + INP-Telemetrie sammeln und Rankings für den nächsten Besuch automatisch anpassen.
  • Priority Hints und fetchpriority verbinden: HTML-Default (low) vom Service Worker überschreiben und bei Bedarf auf auto/high stellen.
  • Background Sync für Retry: Bei Offline/Low-Bandwidth abbrechen und via periodicSync über Nacht neu versuchen.
  • Observability: Prefetch-Erfolg und ΔLCP in performance-guardian loggen, um das Budget zu überwachen.

Budgetmodell entwerfen

MetrikErfassungEmpfohlene FrequenzZweck
downlinknavigator.connection.downlinkSitzungsstart & NetzwechselBandbreitenabschätzung
effectiveTypeNetwork Information APIJeder Lauf3G/4G/5G-Erkennung
inpP75PerformanceObserver + RUMJeder LaufWarnung bei INP-Verschlechterung
lcpCandidateSizeperformance.getEntriesByType('largest-contentful-paint')Wenn LCP fixiertGröße der LCP-Ressource
prefetchSuccessRateService-Worker-LogsTäglichPrefetch-Wirkung bewerten

Prefetch ist situationsabhängig; diese Signale entscheiden, ob aktuell Budget existiert.

// sw/budget.ts
export function calculateBudget({ downlink, lcpSize, concurrentLoads }: {
  downlink: number
  lcpSize: number
  concurrentLoads: number
}) {
  const capacity = downlink * 125000 // Mbps -> bytes/s
  const reserved = lcpSize + concurrentLoads * 150000
  return Math.max(0, capacity * 0.25 - reserved)
}

Prefetch-Queue aufbauen

Kandidaten werden in prefetch-manifest.json gepflegt.

[
  {
    "id": "hero-day2",
    "url": "/images/event/day2@2x.avif",
    "priority": 0.9,
    "type": "image",
    "expectedSize": 320000
  },
  {
    "id": "gallery-mini",
    "url": "/images/gallery/thumbs.webp",
    "priority": 0.4,
    "type": "image",
    "expectedSize": 90000
  }
]

Der Service Worker lädt das Manifest und reiht nur ein, was innerhalb des Budgets bleibt.

// sw/prefetch.ts
import { calculateBudget } from './budget'
import manifest from '../prefetch-manifest.json'

self.addEventListener('message', event => {
  if (event.data?.type !== 'INIT_PREFETCH') return
  const state = event.data.state
  const budget = calculateBudget({
    downlink: state.downlink,
    lcpSize: state.lcpSize,
    concurrentLoads: state.concurrentLoads
  })
  const queue = manifest
    .filter(item => item.expectedSize <= budget)
    .sort((a, b) => b.priority - a.priority)
  prefetchQueue(queue)
})

async function prefetchQueue(queue) {
  for (const entry of queue) {
    const controller = new AbortController()
    const timeout = setTimeout(() => controller.abort(), 4000)
    try {
      await fetch(entry.url, {
        priority: entry.priority > 0.7 ? 'high' : 'low',
        signal: controller.signal
      })
      await caches.open('prefetch-v1').then(cache => cache.add(entry.url))
      logPrefetch(entry.id, true)
    } catch (error) {
      logPrefetch(entry.id, false, error)
    } finally {
      clearTimeout(timeout)
    }
  }
}

fetchpriority ist noch experimentell, wird aber in Chrome/Safari unterstützt. Für Browser ohne priority-Option einen Fallback implementieren, der das <link fetchpriority>-Attribut anpasst.

Priority Hints mit HTML verbinden

// app/layout.tsx
export function PrefetchHints() {
  return (
    <>
      <link
        rel="preload"
        as="image"
        href="/images/event/day2@2x.avif"
        fetchPriority="low"
      />
      <script
        dangerouslySetInnerHTML={{
          __html: `navigator.serviceWorker?.controller?.postMessage({
            type: 'INIT_PREFETCH',
            state: {
              downlink: navigator.connection?.downlink || 1.5,
              lcpSize: window.__LCP_SIZE__ || 200000,
              concurrentLoads: window.__IN_FLIGHT__ || 0
            }
          });`
        }}
      />
    </>
  )
}

Cancel-Strategie zum Schutz des INP

Steigt das INP, Prefetch sofort stoppen und Prioritäten für kommende Sitzungen senken.

// sw/inp-monitor.ts
const INP_THRESHOLD = 200

new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.duration > INP_THRESHOLD) {
      self.registration.active?.postMessage({ type: 'CANCEL_PREFETCH' })
      updatePriority(entry.eventType)
    }
  }
}).observe({ type: 'event', buffered: true })

CANCEL_PREFETCH stoppt die Queue; priority um 0,1 zu reduzieren sorgt dafür, dass Seiten mit schweren Interaktionen Prefetch eigenständig zurückfahren.

Background Sync & nächtliches Prefetch

Erzwungenes Prefetch auf schlechten Verbindungen blockiert die UI. Mit periodicSync erneut versuchen, sobald Wi-Fi oder Ruhezeiten anliegen.

// sw/background-sync.ts
self.addEventListener('sync', event => {
  if (event.tag !== 'prefetch-sync') return
  event.waitUntil(prefetchQueue(manifest))
})

async function scheduleSync() {
  const registration = await self.registration.periodicSync?.register('prefetch-sync', {
    minInterval: 6 * 60 * 60 * 1000
  })
  return registration
}

Monitoring & Analytics

Sende RUM-Events an performance-guardian, um den Nutzen zu prüfen.

sendToAnalytics('prefetch', {
  budget,
  downlink,
  prefetchSuccessRate,
  deltaLCP,
  deltaINP
})

Dashboard-KPIs:

KPIZielwertAlarmbedingung
ΔLCP (mit vs ohne Prefetch)≈ -180 ms3 Tage positive Werte → Alarm
INP p75< 180 ms> 200 ms → sofort stoppen
Prefetch Success Rate> 85%< 70% → Manifest anpassen
Bandbreitenanteil< 30%> 50% → Experiment pausieren

Checklist

  • [ ] prefetch-manifest.json wird gecodereviewt.
  • [ ] Parameter von calculateBudget per A/B-Test verifiziert.
  • [ ] Prefetch stoppt sofort bei INP-Verschlechterung.
  • [ ] Background Sync versucht erneut nur bei Wi-Fi.
  • [ ] performance-guardian visualisiert ΔLCP/ΔINP.
  • [ ] CDN-Cache-Hitrate vor/nach Rollout verglichen.

Fazit

Ungebremstes Prefetching verschlingt Bandbreite und schadet dem INP. Mit Budgetmodell, dynamischer Priorisierung und Background Sync lässt sich Prefetch konditionieren: LCP verbessert sich, die UX bleibt geschmeidig. Kombiniere Browser-APIs mit CI-Automation, baue Kontrollschleifen und entwickle die Prefetch-Strategie je Site weiter.

Verwandte Artikel

Komprimierung

Loss-aware Streaming Throttling 2025 — AVIF/HEIC-Bandbreitensteuerung mit Qualitäts-SLOs

Praxisleitfaden für das Gleichgewicht zwischen Bandbreitendrosselung und Qualitäts-SLOs bei der Auslieferung hoch komprimierter Formate wie AVIF/HEIC. Enthält Kontrollmuster, Monitoring und Rollback-Strategien.

Arbeitsabläufe

Bildoptimierung mit einem WASM-Build-Pipeline 2025 automatisieren — esbuild und Lightning CSS in der Praxis

Muster zur Automatisierung von Derivat-Erzeugung, Validierung und Signatur in einer WASM-fähigen Build-Kette. Zeigt, wie esbuild, Lightning CSS und Squoosh CLI für reproduzierbares CI/CD zusammenspielen.

Komprimierung

Ultimative Bildkomprimierung-Strategie 2025 — Praktischer Leitfaden zur Performance-Optimierung bei Qualitätserhalt

Umfassende Aufschlüsselung der neuesten Bildkomprimierungsstrategien für Core Web Vitals und reale Betriebsumgebungen, mit spezifischen Presets, Code und Workflows nach Anwendungsfall. Umfasst JPEG/PNG/WebP/AVIF-Auswahl, Build/Delivery-Optimierung und Fehlerbehebung.

Web

CDN Service Level Auditor 2025 — SLA-Nachweise für die Bildauslieferung

Audit-Architektur, mit der Multi-CDN-Setups ihre Bild-SLAs belegen. Behandelt Messstrategie, Beweissicherung und verhandlungsreife Reports.

Web

Core Web Vitals Monitoring in der Praxis 2025 — SRE-Checkliste für Enterprise-Projekte

Ein praxisnahes SRE-Playbook für Enterprise-Teams, das Core Web Vitals in den täglichen Betrieb überführt – von SLO-Design über Datenerfassung bis zur Incident-Response.

Komprimierung

Edge-Bildauslieferungs-Observability 2025 — SLO-Design und Betriebsleitfaden für Webagenturen

Beschreibt SLO-Design, Messdashboards und Alarmbetrieb, um Bildauslieferungsqualität über Edge-CDNs und Browser zu beobachten, inklusive Next.js- und GraphQL-Beispiellösungen für Webagenturen.