Service Workers: สร้าง Offline Experience ด้วย JavaScript
ในโลกของการพัฒนาเว็บสมัยใหม่ ประสบการณ์การใช้งานที่ราบรื่นและรวดเร็วถือเป็นสิ่งสำคัญอย่างยิ่ง Service Workers เข้ามามีบทบาทสำคัญในการตอบโจทย์นี้ โดยเฉพาะอย่างยิ่งในเรื่องของการสร้าง offline experience และการเพิ่มประสิทธิภาพของเว็บไซต์โดยรวม บทความนี้จะพาคุณไปทำความเข้าใจ Service Workers ตั้งแต่พื้นฐาน ไปจนถึงการใช้งานจริง
Service Worker คืออะไร?
Service Worker คือ JavaScript script ที่ทำงานอยู่เบื้องหลัง (background) ใน browser ของผู้ใช้งาน โดยทำงานแยกจากหน้าเว็บหลัก และสามารถเข้าถึงทรัพยากรต่างๆ ของ browser ได้โดยตรง Service Workers ทำหน้าที่เป็น proxy ระหว่าง browser และ network ทำให้นักพัฒนาสามารถควบคุมการ request ต่างๆ ได้ รวมถึงการจัดการ cache และการส่ง push notifications
เหตุผลเชิงออกแบบ: Service Workers ถูกออกแบบมาเพื่อแก้ไขปัญหา latency และ reliability ของเว็บแอปพลิเคชัน โดยการอนุญาตให้เว็บแอปพลิเคชันทำงานได้แม้ในขณะที่ไม่มีการเชื่อมต่ออินเทอร์เน็ต หรือมีการเชื่อมต่อที่ไม่เสถียร
Service Worker Lifecycle
Service Worker มีวงจรชีวิต (lifecycle) ที่สำคัญ 3 ขั้นตอน:
- Registration: ขั้นตอนแรกคือการลงทะเบียน Service Worker กับ browser โดยใช้ JavaScript ในหน้าเว็บหลัก
- Installation: หลังจากลงทะเบียนแล้ว Service Worker จะถูกติดตั้ง (installed) ในขั้นตอนนี้เรามักจะทำการ cache ทรัพยากรที่จำเป็นสำหรับ offline experience เช่น HTML, CSS, JavaScript, และ images
- Activation: เมื่อ Service Worker ติดตั้งเสร็จสมบูรณ์และพร้อมใช้งาน จะเข้าสู่สถานะ activation ในขั้นตอนนี้เราสามารถล้าง cache เก่า หรือทำการ migrate ข้อมูลที่จำเป็น
ตัวอย่างโค้ด: การลงทะเบียน Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
คำอธิบาย: โค้ดนี้จะตรวจสอบว่า browser รองรับ Service Workers หรือไม่ หากรองรับ จะทำการลงทะเบียน Service Worker ที่ไฟล์ /service-worker.js
ตัวอย่างโค้ด: service-worker.js (Installation)
const CACHE_NAME = 'my-site-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/style.css',
'/script.js',
'/images/logo.png'
];
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
คำอธิบาย: โค้ดนี้จะสร้าง event listener สำหรับ install event ซึ่งจะเกิดขึ้นเมื่อ Service Worker ถูกติดตั้ง ใน event handler เราจะทำการเปิด cache ที่มีชื่อว่า my-site-cache-v1 และเพิ่มไฟล์ที่ระบุไว้ใน urlsToCache ลงใน cache
ตัวอย่างโค้ด: service-worker.js (Activation)
self.addEventListener('activate', function(event) {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
คำอธิบาย: โค้ดนี้จะสร้าง event listener สำหรับ activate event ซึ่งจะเกิดขึ้นเมื่อ Service Worker ถูก activate ใน event handler เราจะทำการล้าง cache เก่าที่ไม่ตรงกับ CACHE_NAME เพื่อให้แน่ใจว่าเราใช้ cache version ล่าสุด
Caching Strategies
การเลือกใช้ caching strategy ที่เหมาะสมเป็นสิ่งสำคัญสำหรับการสร้าง offline experience ที่ดี Caching strategies หลักๆ มีดังนี้:
- Cache First: ตรวจสอบ cache ก่อน หากมีทรัพยากรที่ต้องการใน cache จะใช้ทรัพยากรจาก cache หากไม่มี จะทำการ request จาก network และ cache ทรัพยากรนั้นไว้
- Network First: ทำการ request จาก network ก่อน หาก request สำเร็จ จะใช้ทรัพยากรจาก network และ cache ทรัพยากรนั้นไว้ หาก request ล้มเหลว จะใช้ทรัพยากรจาก cache
- Cache Only: ใช้ทรัพยากรจาก cache เท่านั้น
- Network Only: ทำการ request จาก network เท่านั้น
- Stale-While-Revalidate: ใช้ทรัพยากรจาก cache ทันที และทำการ request จาก network เพื่ออัปเดต cache ใน background
ตัวอย่างโค้ด: service-worker.js (Cache First Strategy)
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
// IMPORTANT: Clone the request. A request is a stream and
// can only be consumed once. Since we are consuming this
// once by cache and once by the fetch, we need to clone.
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function(response) {
// Check if we received a valid response
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT: Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as cache it we need to clone it so we have two.
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
คำอธิบาย: โค้ดนี้จะสร้าง event listener สำหรับ fetch event ซึ่งจะเกิดขึ้นเมื่อ browser ทำการ request ทรัพยากร ใน event handler เราจะตรวจสอบว่าทรัพยากรนั้นมีอยู่ใน cache หรือไม่ หากมี จะส่งทรัพยากรจาก cache หากไม่มี จะทำการ request จาก network และ cache ทรัพยากรนั้นไว้
เหตุผลเชิงออกแบบ: การเลือกใช้ caching strategy ขึ้นอยู่กับลักษณะของทรัพยากรและข้อกำหนดของแอปพลิเคชัน ตัวอย่างเช่น สำหรับทรัพยากรที่ไม่ค่อยมีการเปลี่ยนแปลง เช่น logo หรือ CSS, Cache First strategy อาจเป็นทางเลือกที่ดี สำหรับทรัพยากรที่ต้องการความสดใหม่ เช่น ข้อมูลจาก API, Network First หรือ Stale-While-Revalidate อาจเหมาะสมกว่า
Push Notifications
Service Workers ยังสามารถใช้เพื่อส่ง push notifications ให้กับผู้ใช้งานได้ แม้ว่าผู้ใช้งานจะไม่ได้เปิดหน้าเว็บนั้นอยู่ก็ตาม Push notifications เป็นเครื่องมือที่มีประสิทธิภาพในการดึงดูดผู้ใช้งานกลับมายังแอปพลิเคชันของคุณ
ขั้นตอนการใช้งาน Push Notifications:
- Request Permission: ขอ permission จากผู้ใช้งานเพื่อส่ง push notifications
- Subscribe to Push Service: สมัครสมาชิก (subscribe) กับ push service (เช่น Firebase Cloud Messaging) เพื่อรับ push subscription object
- Send Push Notification: ส่ง push notification ไปยัง push service โดยใช้ push subscription object
- Handle Push Notification: ใน Service Worker, handle
pushevent เพื่อแสดง notification ให้กับผู้ใช้งาน
ตัวอย่างโค้ด: service-worker.js (Handle Push Notification)
self.addEventListener('push', function(event) {
const notificationData = event.data.json();
const title = notificationData.title || 'Default Title';
const options = {
body: notificationData.body || 'Default Body',
icon: notificationData.icon || '/images/icon.png',
badge: notificationData.badge || '/images/badge.png'
};
event.waitUntil(self.registration.showNotification(title, options));
});
คำอธิบาย: โค้ดนี้จะสร้าง event listener สำหรับ push event ซึ่งจะเกิดขึ้นเมื่อ push notification ถูกส่งมา ใน event handler เราจะดึงข้อมูลจาก notification data และแสดง notification ให้กับผู้ใช้งาน
ข้อควรระวัง: การใช้งาน push notifications ควรคำนึงถึงประสบการณ์ของผู้ใช้งาน และไม่ส่ง notifications ที่ไม่เกี่ยวข้องหรือรบกวนผู้ใช้งาน
สรุป
Service Workers เป็นเครื่องมือที่ทรงพลังในการสร้าง offline experience และเพิ่มประสิทธิภาพของเว็บไซต์ การทำความเข้าใจ lifecycle, caching strategies, และการใช้งาน push notifications จะช่วยให้คุณสามารถสร้างเว็บแอปพลิเคชันที่รวดเร็ว น่าเชื่อถือ และดึงดูดผู้ใช้งานได้มากยิ่งขึ้น