ข้ามไปยังเนื้อหา

Cache-First และ Network-First

caching strategy พื้นฐานที่สุดสองตัวคือ cache-first และ network-first

cache-first ให้ความสำคัญกับความเร็ว service worker เสิร์ฟจาก cache ทันทีและแตะ network เฉพาะตอนที่ cache miss เท่านั้น จึงเหมาะที่สุดสำหรับ app shell, ฟอนต์, icon, และ static asset อื่น ๆ ที่เปลี่ยนแปลงไม่บ่อย

ส่วน network-first ให้ความสำคัญกับความสดใหม่ โดยพยายาม fetch สด ๆ เสมอและ fallback ไปที่ cache เฉพาะตอนที่ network ใช้งานไม่ได้ จึงเป็นตัวเลือกที่ถูกต้องสำหรับการตอบกลับจาก API, หน้า HTML แบบไดนามิก, และ resource ใด ๆ ที่การเสิร์ฟข้อมูลเก่าจะก่อให้เกิดความเสียหาย

การเลือกระหว่างสองตัวนี้คือการแลกเปลี่ยน: cache-first ให้การโหลดทันทีโดยเสี่ยงกับเนื้อหาที่เก่า; network-first ให้เนื้อหาสดใหม่โดยแลกกับ network round-trip ในทุก request

เสิร์ฟจาก cache ทันที fetch จาก network เฉพาะตอนที่ cache miss แล้วค่อยแคชผลลัพธ์ไว้สำหรับครั้งถัดไป strategy นี้เหมาะที่สุดสำหรับ static asset ที่เปลี่ยนแปลงไม่บ่อย — JavaScript bundle, CSS stylesheet, web font, และรูปภาพ เพราะ cache ถูกตรวจสอบก่อน network หน้าเพจจึงโหลดเร็วระดับ memory แม้บนการเชื่อมต่อที่ช้า

วินัยสำคัญของ cache-first คือ การทำ cache versioning: เพราะ asset ถูกเสิร์ฟจาก cache โดยไม่ปรึกษา network คุณจึงต้องเพิ่มเลขชื่อ cache (เช่นจาก app-v1 เป็น app-v2) ทุกครั้งที่คุณ deploy asset ใหม่ และลบ cache เก่าใน activate event เพื่อคืนพื้นที่จัดเก็บ

const CACHE = 'app-v1';
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
if (cached) return cached;
return fetch(event.request).then((response) => {
return caches.open(CACHE).then((cache) => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});
flowchart LR
  A[Request] --> B{Check cache}
  B -- hit --> C[Return cached response]
  B -- miss --> D[Fetch from network]
  D --> E[Store in cache]
  E --> F[Return response]
strategy แบบ cache-first

ลอง network ก่อนเสมอ เมื่อ network ล้มเหลวจึง fallback ไปที่ cache วิธีนี้เหมาะที่สุดสำหรับข้อมูลไดนามิกที่คุณต้องการความสดใหม่ — การตอบกลับ JSON จาก API, HTML ที่ render จาก server — แต่ก็ยังต้องการความทนทานแบบออฟไลน์เพื่อไม่ให้ผู้ใช้ต้องจ้องหน้าเพจว่างเปล่า

ข้อแลกเปลี่ยนคือทุก request ที่สำเร็จต้องจ่ายค่า network round-trip เต็ม ๆ หน้าเพจจึงโหลดได้ไม่เร็วกว่าที่ server ตอบกลับ บนการเชื่อมต่อที่ช้านี่ช้ากว่า cache-first อย่างเห็นได้ชัด network-first จึงเป็นตัวเลือกที่ผิดสำหรับ static asset ขนาดใหญ่ ให้สงวนไว้สำหรับ resource ที่ข้อมูลเก่ายอมรับไม่ได้จริง ๆ

const CACHE = 'app-v1';
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request)
.then((response) => {
return caches.open(CACHE).then((cache) => {
cache.put(event.request, response.clone());
return response;
});
})
.catch(() => caches.match(event.request))
);
});
flowchart LR
  A[Request] --> B[Fetch from network]
  B -- success --> C[Store in cache]
  C --> D[Return response]
  B -- failure --> E{Check cache}
  E -- hit --> F[Return cached response]
  E -- miss --> G[Return undefined / error]
strategy แบบ network-first

เดโมด้านล่างลงทะเบียน service worker ที่ใช้ cache-first สำหรับทุก request เปิดโปรเจกต์ StackBlitz โหลดหน้าเพจหนึ่งครั้งเพื่อให้ SW ติดตั้ง แล้ว reload — การโหลดครั้งที่สองจะถูกเสิร์ฟจาก cache ทั้งหมด เปิด DevTools → Application → Cache Storage เพื่อดูรายการที่ถูกแคชไว้

Runs a real service worker + manifest in your browser.
ตัวเลือกBenefitCost
Cache-firstโหลดเร็วที่สุด เหมาะกับ static asset ที่เปลี่ยนไม่บ่อยเสี่ยง serve เนื้อหาเก่าถ้า asset เปลี่ยนแต่ cache ไม่ถูก invalidate
Network-firstได้ข้อมูลสดใหม่เสมอเมื่อ network พร้อมช้ากว่า cache-first ทุก request เพราะต้องรอ network round-trip ก่อนเสมอ
  • ใช้ cache-first กับ API response ที่เปลี่ยนบ่อย ทำให้ผู้ใช้เห็นข้อมูลเก่าโดยไม่รู้ตัว
  • ใช้ network-first กับ static asset ขนาดใหญ่ ทำให้เสียเวลาโหลดโดยไม่จำเป็นทั้งที่ asset แทบไม่เปลี่ยน
  • ไม่ตั้ง timeout ให้ network-first ทำให้ผู้ใช้ต้องรอ network ที่ช้ามากแทนที่จะ fallback ไป cache เร็วกว่านี้

💡 ตัวอย่างจากของจริง

Twitter Lite / Pinterest — ใช้ Workbox ผสมทั้ง cache-first (asset) และ network-first (feed data) ในแอปเดียว ให้เหมาะกับแต่ละประเภท resource

BBC News — ใช้ network-first สำหรับข่าวด่วนเพื่อความสดใหม่ แต่ cache-first สำหรับ layout/asset เพื่อความเร็ว

strategy ใดที่ลอง network ก่อนและจะ fallback ไปที่ cache เฉพาะตอนล้มเหลวเท่านั้น?
Cache-first เหมาะสมที่สุดสำหรับ:
คุณจะ invalidate asset แบบ cache-first ที่เก่าหลัง deploy ได้อย่างไร?
fetch handler แบบ network-first คืนค่าอะไรเมื่อทั้ง network และ cache ล้มเหลว?