Cache-First และ Network-First
Cache-first และ network-first
หัวข้อที่มีชื่อว่า “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-first
หัวข้อที่มีชื่อว่า “Cache-first”เสิร์ฟจาก 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] Network-first
หัวข้อที่มีชื่อว่า “Network-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] ลองใช้งานจริง
หัวข้อที่มีชื่อว่า “ลองใช้งานจริง”เดโมด้านล่างลงทะเบียน service worker ที่ใช้ cache-first สำหรับทุก request เปิดโปรเจกต์ StackBlitz โหลดหน้าเพจหนึ่งครั้งเพื่อให้ SW ติดตั้ง แล้ว reload — การโหลดครั้งที่สองจะถูกเสิร์ฟจาก cache ทั้งหมด เปิด DevTools → Application → Cache Storage เพื่อดูรายการที่ถูกแคชไว้
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| 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 เพื่อความเร็ว