กลับไปหน้าบทความ
#Service Worker#PWA#Web Performance#Offline Page#Cache Strategy

Service Worker ทำ Offline Page และ Cache อัจฉริยะให้เว็บลื่นแม้เน็ตหลุด

Service Worker คือหัวใจสำคัญที่ช่วยให้เว็บทำงานได้ใกล้เคียงแอปมากขึ้น ทั้งการแสดงหน้าออฟไลน์และจัดการแคชอย่างชาญฉลาด บทความนี้สรุปแนวคิด วิธีเริ่มต้น และกลยุทธ์ cache ที่ใช้ได้จริงกับเว็บส่วนใหญ่

8 กุมภาพันธ์ 2569อ่านประมาณ 2 นาที

แชร์บทความ

Service Worker ทำ Offline Page และ Cache อัจฉริยะให้เว็บลื่นแม้เน็ตหลุด

Service Worker ทำ Offline Page และ Cache อัจฉริยะให้เว็บลื่นแม้เน็ตหลุด

หลายคนรู้จักคำว่า PWA กันอยู่แล้ว แต่สิ่งที่ทำให้เว็บมีประสบการณ์ใกล้เคียงแอปจริง ๆ มักอยู่ที่ Service Worker ซึ่งเป็นสคริปต์ที่ทำงานอยู่เบื้องหลังและสามารถดักจับคำขอจากหน้าเว็บเพื่อกำหนดว่าจะตอบกลับด้วยข้อมูลจากเครือข่ายหรือจาก cache

จุดเด่นของ Service Worker ไม่ได้มีแค่การทำให้เว็บเปิดได้ตอนออฟไลน์ แต่คือความสามารถในการวางกติกาอย่างชัดเจนว่า ไฟล์ไหนควรเก็บไว้ใช้ซ้ำ ไฟล์ไหนควรสดใหม่ และข้อมูลไหนยอม fallback ได้เมื่ออินเทอร์เน็ตมีปัญหา สิ่งนี้ช่วยยกระดับ UX ของเว็บให้เร็วขึ้น ลื่นขึ้น และดูเป็นมืออาชีพมากขึ้นอย่างชัดเจน

ทำไมคนทำเว็บควรสนใจเรื่องนี้

การทำ Offline Page และวางกลยุทธ์ cache ที่ดีมีผลกับทั้งประสิทธิภาพและประสบการณ์ใช้งานโดยตรง เช่น

  • ลดโอกาสที่ผู้ใช้จะปิดเว็บทันทีเมื่อเน็ตแกว่งหรือโหลดไม่ขึ้น
  • ทำให้หน้าเดิม ๆ เปิดได้เร็วขึ้น เพราะบางทรัพยากรถูกเก็บไว้ในเครื่องแล้ว
  • ช่วยประหยัดดาต้าสำหรับผู้ใช้ โดยเฉพาะบนมือถือ
  • ทำให้ประสบการณ์ใช้งานดูใกล้เคียงแอปมากขึ้น

ในโลกจริง ผู้ใช้ไม่ได้มีอินเทอร์เน็ตที่เสถียรตลอดเวลา ดังนั้นเว็บที่รับมือกับสถานการณ์เหล่านี้ได้ดีมักได้เปรียบทั้งในแง่การใช้งานและภาพลักษณ์

Service Worker คืออะไร

Service Worker เป็นสคริปต์ที่รันแยกจากหน้าเว็บหลัก ทำหน้าที่คล้ายตัวกลางหรือ proxy ของเว็บ เมื่อมี request เกิดขึ้น Service Worker สามารถตัดสินใจได้ว่าจะ

  • ส่งคำขอไปที่ network
  • ตอบกลับจาก cache
  • หรือส่งหน้า fallback เมื่อโหลดจริงไม่ได้

ไฟล์หลักที่มักใช้มี 2 ส่วนคือ

  1. /sw.js สำหรับเขียน logic ของ Service Worker
  2. /offline.html สำหรับเป็นหน้าสำรองเมื่อผู้ใช้ออฟไลน์

แนวคิดนี้ทำให้เราควบคุมพฤติกรรมของเว็บได้ละเอียดกว่าการพึ่ง browser cache แบบปกติ

ขั้นตอนเริ่มต้นแบบจำง่าย

การใช้งาน Service Worker โดยทั่วไปเริ่มจาก 4 ขั้นตอนหลัก

  1. ลงทะเบียน Service Worker ในหน้าเว็บ
  2. ตอน install ให้ pre-cache ไฟล์สำคัญ
  3. ตอน fetch เลือกกลยุทธ์ cache ให้เหมาะกับประเภทของ resource
  4. หากออฟไลน์ ให้ส่งหน้า offline.html แทน error page

ตัวอย่างการลงทะเบียนใน main.js

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}

ตัวอย่าง install และ pre-cache ใน sw.js

const CACHE_NAME = 'v1-static';
const ASSETS = ['/', '/offline.html', '/styles.css', '/main.js', '/logo.png'];

self.addEventListener('install', event => {
  event.waitUntil(caches.open(CACHE_NAME).then(cache => cache.addAll(ASSETS)));
});

วิธีนี้ช่วยให้ไฟล์สำคัญพร้อมใช้งานแม้ตอนที่เครือข่ายมีปัญหา

Offline Page ที่ดีควรมีอะไรบ้าง

หน้าออฟไลน์ที่ดีไม่ควรมีแค่ข้อความว่า “อินเทอร์เน็ตขัดข้อง” แล้วจบ แต่ควรช่วยให้ผู้ใช้ไปต่อได้ เช่น

  • มีปุ่มกลับหน้าแรก
  • อธิบายสถานะอย่างชัดเจนว่าเกิดอะไรขึ้น
  • แสดงข้อมูลล่าสุดที่เคย cache ไว้ หากเป็นไปได้
  • ออกแบบให้ยังดูเป็นส่วนหนึ่งของเว็บไซต์เดิม

เมื่อผู้ใช้รู้สึกว่าเว็บยังพาเขาไปต่อได้ แม้เน็ตจะหลุด ประสบการณ์โดยรวมจะดีขึ้นมาก

กลยุทธ์ Cache ที่ควรเลือกให้ถูกงาน

หัวใจของการใช้ Service Worker คือการเลือก cache strategy ให้เหมาะกับทรัพยากรแต่ละประเภท ไม่ควรใช้วิธีเดียวกับทุกอย่าง

1) Cache First

เหมาะกับไฟล์นิ่ง เช่น CSS, JavaScript, ฟอนต์ หรือโลโก้

ข้อดีคือเร็วมาก เพราะโหลดจาก cache ก่อนทันที แต่ต้องจัดการเวอร์ชันให้ดี ไม่อย่างนั้นผู้ใช้อาจเห็นไฟล์เก่านานเกินไป

2) Network First

เหมาะกับหน้าเนื้อหาที่ควรอัปเดต เช่น บทความ หน้าโปรไฟล์ หรือข้อมูลที่ต้องการความสดใหม่

วิธีนี้จะพยายามโหลดจาก network ก่อน หากไม่สำเร็จจึงค่อยใช้ข้อมูลจาก cache เป็นตัวสำรอง

3) Stale-While-Revalidate

เหมาะกับข้อมูลที่เก่าได้เล็กน้อย เช่น รายการสินค้า หรือ API ที่ไม่จำเป็นต้องใหม่แบบวินาทีต่อวินาที

แนวทางนี้จะส่งข้อมูลจาก cache ให้เร็วที่สุดก่อน แล้วจึงไปอัปเดตข้อมูลใหม่ในเบื้องหลัง ทำให้ทั้งเร็วและยังมีโอกาสได้ข้อมูลล่าสุดในการใช้งานครั้งถัดไป

ตัวอย่างการทำ Offline Fallback

หากต้องการให้หน้า HTML แสดง offline.html เมื่อเน็ตหลุด สามารถทำได้ดังนี้

self.addEventListener('fetch', event => {
  const req = event.request;
  if (req.mode === 'navigate') {
    event.respondWith(
      fetch(req).catch(() => caches.match('/offline.html'))
    );
  }
});

แนวทางนี้เหมาะมากกับการทำหน้า fallback สำหรับการเปิดเพจหลักของเว็บไซต์

ตัวอย่าง Stale-While-Revalidate สำหรับ API

สำหรับ API แบบ GET ที่รับได้หากข้อมูลเก่าเล็กน้อย กลยุทธ์ SWR เป็นตัวเลือกที่ดี

async function swr(request) {
  const cache = await caches.open('v1-api');
  const cached = await cache.match(request);
  const network = fetch(request).then(res => {
    if (res.ok) cache.put(request, res.clone());
    return res;
  }).catch(() => cached);
  return cached || network;
}

ข้อดีคือผู้ใช้ได้รับผลลัพธ์เร็ว ขณะเดียวกันระบบก็ยังอัปเดตข้อมูลใหม่ให้โดยอัตโนมัติเมื่อเครือข่ายพร้อม

ข้อผิดพลาดที่พบบ่อยในการทำ Cache

สิ่งที่หลายคนพลาดคือการ cache ทุกอย่างแบบไม่แยกประเภท ซึ่งสร้างปัญหาตามมาได้หลายอย่าง เช่น

  • ข้อมูลค้างนานเกินไปจนไม่ตรงกับของจริง
  • พื้นที่จัดเก็บโตขึ้นโดยไม่จำเป็น
  • ตรวจสอบและ debug ได้ยาก

กติกาที่ควรยึดคือ แยก cache ตามชนิดของข้อมูล เช่น

  • static cache สำหรับไฟล์นิ่ง
  • api cache สำหรับข้อมูลจาก API
  • page cache สำหรับหน้า HTML หากต้องการ

อีกเรื่องสำคัญคือ Cache Storage ไม่ได้เชื่อฟัง HTTP cache-control เสมอไป หากเราเป็นคนจัดการ cache เอง เราก็ต้องเป็นคนกำหนดอายุ การล้าง และกติกาการอัปเดตเองด้วย

การจัดการเวอร์ชันและล้าง Cache เก่า

วิธีง่ายที่สุดในการจัดการเวอร์ชันคือเปลี่ยนชื่อ cache เมื่อปล่อยของใหม่ เช่นจาก v1-static เป็น v2-static แล้วล้าง cache เก่าทิ้งในช่วง activate

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(keys =>
      Promise.all(keys.filter(k => !['v1-static','v1-api'].includes(k)).map(k => caches.delete(k)))
    )
  );
});

การทำแบบนี้ช่วยลดปัญหาไฟล์เก่าค้างและทำให้ควบคุมการอัปเดตได้ง่ายขึ้น

เรื่องความปลอดภัยที่ต้องรู้

Service Worker ใช้งานได้เฉพาะบน HTTPS เท่านั้น ยกเว้นกรณี localhost สำหรับพัฒนาในเครื่อง เพราะ Service Worker มีสิทธิ์เข้าถึงและดัก request ของเว็บได้ในระดับที่ทรงพลังมาก จึงต้องมีข้อกำหนดด้านความปลอดภัยที่เข้มงวด

แนวทางใช้งานจริงที่เหมาะกับเว็บส่วนใหญ่

ถ้าต้องการเริ่มใช้งานแบบไม่ซับซ้อนเกินไป สามารถใช้แนวทางนี้ได้

  1. Precache เฉพาะ shell ที่จำเป็น เช่น offline.html, CSS และ JavaScript หลัก
  2. ใช้ runtime cache กับรูป ฟอนต์ และบาง API ตามกลยุทธ์ที่เหมาะ
  3. ตั้งเพดานจำนวนรายการหรืออายุของ cache เพื่อลดปัญหา storage บวม

หากไม่อยากเขียน logic เองทั้งหมด สามารถใช้ Workbox ของ Google เพื่อช่วยเรื่อง routing, strategy และ expiration ได้สะดวกมากขึ้น

ควรเริ่มจากตรงไหน

จุดเริ่มต้นที่ดีคืออย่าพยายามทำทุกอย่างพร้อมกัน ให้เริ่มจากสิ่งที่เห็นผลเร็วที่สุดก่อน เช่น

  • ทำ offline.html หนึ่งหน้า
  • pre-cache ไฟล์นิ่งที่จำเป็น
  • ค่อยเพิ่ม SWR ให้กับ API ที่สำคัญบางจุด

เมื่อทำทีละขั้น จะเห็นผลชัดทั้งในด้านความเร็วและความลื่นของประสบการณ์ใช้งาน

สรุป

Offline Page คือแผนสำรองเมื่อเครือข่ายล้มเหลว แต่สิ่งที่ทำให้เว็บฉลาดจริง ๆ คือ cache strategy ที่เลือกใช้อย่างเหมาะสมกับแต่ละประเภทของข้อมูล

ถ้าทำสองอย่างนี้ควบคู่กัน เว็บจะไม่เพียงเปิดได้ตอนเน็ตหลุด แต่ยังให้ประสบการณ์ใช้งานที่เร็ว เสถียร และดูเป็นมืออาชีพมากขึ้นอย่างชัดเจน การเริ่มต้นจากหน้าออฟไลน์หนึ่งหน้าและ cache ไฟล์นิ่งก่อน คือก้าวแรกที่คุ้มค่ามากสำหรับเว็บแทบทุกประเภท