Mengelola anggaran prefetch gambar di Service Worker 2025 — Prioritas pintar dan INP tetap sehat
Diterbitkan: 29 Sep 2025 · Waktu baca: 5 mnt · Redaksi Unified Image Tools
Banyak tim menambahkan prefetch gambar demi LCP, tetapi Service Worker justru menyedot bandwidth dan memperburuk INP. Tahun 2025, Priority Hints sudah stabil dan Network Information API memberi sinyal lebih akurat, sehingga prefetch bisa dikendalikan secara dinamis. Artikel ini memperlakukan target asset dan timing sebagai “anggaran” dan menjelaskan cara memuat hero ataupun galeri lebih awal tanpa mengorbankan pengalaman pengguna.
TL;DR
- Kuantifikasi anggaran: hitung
budget = (downlink × 0,25) - aset LCP yang sedang dimuat
; hentikan prefetch bila hasilnya negatif. - Re-ranking di Service Worker: kumpulkan telemetri Navigation Timing + INP, lalu sesuaikan peringkat prefetch untuk kunjungan berikutnya.
- Sinkronkan Priority Hints dan
fetchpriority
: timpa nilai HTML (low
) dari Service Worker, ubah keauto
/high
sesuai kondisi. - Coba ulang dengan Background Sync: batalkan saat offline/bandwidth rendah dan jadwalkan ulang via
periodicSync
pada malam hari. - Observabilitas: catat keberhasilan prefetch serta ΔLCP ke performance-guardian untuk mengecek apakah anggaran tepat.
Mendesain model anggaran
Metrik | Cara memperoleh | Frekuensi disarankan | Tujuan |
---|---|---|---|
downlink | navigator.connection.downlink | Awal sesi & perubahan jaringan | Estimasi bandwidth |
effectiveType | Network Information API | Setiap eksekusi | Klasifikasi 3G/4G/5G |
inpP75 | PerformanceObserver + RUM | Setiap eksekusi | Peringatan degradasi INP |
lcpCandidateSize | performance.getEntriesByType('largest-contentful-paint') | Saat LCP final | Memahami ukuran aset LCP |
prefetchSuccessRate | Log Service Worker | Harian | Menilai efektivitas prefetch |
Prefetch bersifat situasional; gunakan sinyal ini untuk memutuskan apakah anggaran tersedia sekarang.
// 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)
}
Membangun antrean prefetch
Kelola kandidat di prefetch-manifest.json
.
[
{
"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
}
]
Service Worker memuat manifest ini dan hanya mengantre item yang masih muat dalam anggaran.
// 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
masih eksperimental tetapi sudah jalan di Chrome/Safari. Untuk browser tanpa opsi priority
, buat fallback yang menulis ulang atribut <link fetchpriority>
.
Menghubungkan Priority Hints dengan HTML
// 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
}
});`
}}
/>
</>
)
}
Strategi pembatalan demi menjaga INP
Saat INP memburuk, hentikan prefetch seketika dan turunkan prioritas untuk sesi berikutnya.
// 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
menghentikan antrean; mengurangi priority
sebanyak 0,1 tiap kejadian membuat halaman dengan interaksi berat menahan prefetch secara alami.
Background Sync dan prefetch malam hari
Memaksa prefetch di koneksi buruk membuat UI macet. Gunakan periodicSync
untuk mencoba lagi saat Wi-Fi atau jam sepi.
// 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 dan analitik
Kirim event RUM ke performance-guardian untuk memantau dampak prefetch.
sendToAnalytics('prefetch', {
budget,
downlink,
prefetchSuccessRate,
deltaLCP,
deltaINP
})
KPI utama:
KPI | Target | Kondisi alert |
---|---|---|
ΔLCP (prefetch vs tanpa) | ≈ -180 ms | Bernilai positif 3 hari berturut-turut |
INP p75 | < 180 ms | > 200 ms → hentikan segera |
Prefetch Success Rate | > 85% | < 70% → revisi manifest |
Penggunaan bandwidth | < 30% | > 50% → jeda eksperimen |
Checklist
- [ ]
prefetch-manifest.json
masuk review kode. - [ ] Parameter
calculateBudget
diuji A/B. - [ ] Prefetch langsung berhenti ketika INP turun kualitas.
- [ ] Background Sync hanya mencoba ulang saat Wi-Fi.
- [ ] performance-guardian memvisualisasikan ΔLCP/ΔINP.
- [ ] Rasio hit cache CDN dibandingkan sebelum/sesudah peluncuran.
Ringkasan
Prefetch tanpa kendali dapat menguras bandwidth dan merusak INP. Dengan model anggaran, prioritas dinamis, dan Background Sync, kamu bisa membuat prefetch bersyarat: LCP naik, pengalaman tetap mulus. Gabungkan API browser dengan otomatisasi CI untuk membangun loop kontrol dan kembangkan strategi prefetch sesuai karakter situs.
Alat terkait
tools.performanceGuardian
toolDescriptions.performanceGuardian
Penggeser perbandingan
Perbandingan sebelum/sesudah yang intuitif.
Anggaran kualitas gambar & gerbang CI
Tetapkan anggaran ΔE2000/SSIM/LPIPS, simulasi gerbang CI, dan ekspor guardrail.
Pencatat audit
Catat tindakan remediasi di lapisan gambar, metadata, dan pengguna dengan jejak audit yang bisa diekspor.
Artikel terkait
Throttling streaming sadar-loss 2025 — Kendali bandwidth AVIF/HEIC dengan SLO kualitas
Panduan praktik untuk menyeimbangkan throttling bandwidth dan SLO kualitas ketika melayani format kompresi tinggi seperti AVIF/HEIC. Bahas pola kontrol streaming, pemantauan, dan strategi rollback.
Mengotomatiskan optimasi gambar dengan pipeline WASM 2025 — Integrasi esbuild dan Lightning CSS
Pola untuk mengotomatiskan pembuatan, validasi, dan penandatanganan derivatif gambar dengan rantai build berbasis WASM. Menjelaskan cara menggabungkan esbuild, Lightning CSS, dan Squoosh CLI agar CI/CD tetap reproducible.
Strategi Kompresi Gambar Lengkap 2025 — Panduan Praktis Optimasi Kecepatan Persepsi sambil Mempertahankan Kualitas
Strategi kompresi gambar terdepan yang efektif untuk Core Web Vitals dan operasi nyata, dengan preset khusus per penggunaan, kode, dan alur kerja yang dijelaskan secara detail. Mencakup pembedaan JPEG/PNG/WebP/AVIF, optimisasi build/delivery, dan diagnosis troubleshooting.
Auditor Layanan CDN 2025 — Memantau SLA gambar berbasis bukti
Arsitektur audit untuk membuktikan kepatuhan SLA gambar di lingkungan multi-CDN. Membahas strategi pengukuran, pengumpulan bukti, dan pelaporan siap negosiasi.
Monitoring Core Web Vitals Praktis 2025 — Checklist SRE untuk proyek enterprise
Playbook bernuansa SRE yang membantu tim produksi web enterprise mengoperasionalkan Core Web Vitals, mencakup desain SLO, pengumpulan data, dan respons insiden secara menyeluruh.
Observabilitas pengiriman gambar Edge 2025 — Panduan desain SLO dan operasi untuk agen web
Mengulas desain SLO, dasbor pengukuran, dan operasi alert untuk memantau kualitas pengiriman gambar melalui Edge CDN dan browser, lengkap dengan contoh implementasi Next.js dan GraphQL bagi agen web.