Service Worker
Script chạy nền ở phía client, cho phép kiểm soát yêu cầu mạng, lưu cache và hỗ trợ PWA và offline experience.
Service Worker là gì?
Service Worker là một script JavaScript chạy nền ở phía trình duyệt (client-side), độc lập với trang web đang mở. Nó hoạt động như một "trung gian" giữa trình duyệt và mạng — có thể chặn, sửa đổi hoặc đáp ứng lại mọi yêu cầu mạng (fetch) từ trang, bao gồm HTML, CSS, JS, hình ảnh, API…
Service Worker chỉ hoạt động trên môi trường HTTPS (trừ localhost dùng cho phát triển), và phải được đăng ký qua JavaScript trên trang chủ. Khi đã được cài đặt và kích hoạt, nó có thể chạy ngay cả khi người dùng đóng tab hoặc rời khỏi trang — điều kiện tiên quyết để xây dựng Progressive Web App (PWA) và trải nghiệm offline.
Tại sao quan trọng trong SEO?
Service Worker không trực tiếp cải thiện thứ hạng trên Google, nhưng ảnh hưởng mạnh đến các yếu tố xếp hạng gián tiếp: tốc độ tải, khả năng truy cập, trải nghiệm người dùng (UX), và tính ổn định trên thiết bị di động — tất cả đều nằm trong Core Web Vitals và là tín hiệu xếp hạng xác nhận bởi Google.
Cụ thể:
- Tăng tốc độ tải lần 2 trở đi: Bằng cách lưu tài nguyên vào cache (cache-first hoặc stale-while-revalidate), Service Worker giúp trang hiển thị gần như tức thì khi người dùng quay lại — giảm thời gian tương tác (TTI) và tăng tỷ lệ giữ chân.
- Hỗ trợ offline & mạng yếu: Người dùng vẫn xem được nội dung đã lưu (ví dụ: bài viết, danh mục sản phẩm), tránh hiện tượng "trang lỗi trắng" — giảm tỷ lệ thoát (bounce rate).
- Cải thiện chỉ số LCP và CLS: Khi tài nguyên tĩnh được phục vụ từ cache thay vì mạng, thời gian render ban đầu ổn định hơn, ít giật/lấp lánh do tải lại CSS/JS.
- Tăng khả năng index: Nếu trang hỗ trợ offline, Googlebot dễ dàng thu thập nội dung hơn trên các phiên crawl chậm hoặc mạng không ổn định — đặc biệt với site có cấu trúc động (SPA).
Cách hoạt động
Service Worker vận hành qua 3 trạng thái chính:
- Đăng ký (Registration): Trình duyệt đọc file
sw.jstừ domain gốc, sau đó tạo instance Service Worker nếu chưa có. - Cài đặt (Installing): Script chạy lệnh
self.skipWaiting()hoặc chờ các tab cũ đóng. Giai đoạn này thường dùng để precache tài nguyên cần thiết. - Kích hoạt (Activated): Service Worker bắt đầu kiểm soát trang (control all clients). Lúc này nó có thể lắng nghe sự kiện
fetch,push,sync…
Lưu ý: Service Worker không có quyền truy cập vào window, document hay DOM — nên không thể thay đổi HTML trực tiếp. Mọi tương tác với trang phải qua postMessage().
Hướng dẫn thực hiện
Dưới đây là các bước triển khai cơ bản, an toàn cho SEO:
- Bắt buộc dùng HTTPS: Nếu chưa có chứng chỉ SSL/TLS, không thể triển khai Service Worker ngoài localhost.
- Tạo file
sw.jsở thư mục gốc: Đảm bảo đường dẫn truy cập là/sw.js(không được đặt sâu hơn, trừ khi khai báo rõ scope). - Đăng ký trong file JavaScript chính:
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(reg => console.log('SW registered')) .catch(err => console.error('SW registration failed:', err)); }); } - Viết logic cache hợp lý: Ưu tiên chiến lược
cache-firstcho tài nguyên tĩnh (CSS, JS, hình ảnh), vànetwork-firstcho nội dung động (API, HTML trang chi tiết) — tránh cache sai gây lỗi hiển thị. - Thêm xử lý lỗi 404 offline: Dùng
respondWith()để trả về trangoffline.htmlkhi fetch thất bại — đảm bảo người dùng luôn thấy nội dung thay vì màn hình trắng. - Thử nghiệm kỹ: Kiểm tra bằng DevTools > Application > Service Workers: nhấn "Update on reload", chọn "Offline" và thử tải lại trang.
Lỗi thường gặp
| Lỗi | Nguyên nhân | Cách khắc phục |
|---|---|---|
| Service Worker không đăng ký | File sw.js không ở thư mục gốc, hoặc thiếu HTTPS |
Đặt sw.js tại /sw.js; kiểm tra chứng chỉ SSL; dùng localhost để test |
| Trang không hoạt động offline | Chưa cache HTML hoặc cache HTML nhưng không có fallback 404 | Cache file index.html và thêm event.respondWith(cachedHtml || offlinePage) |
| Hiển thị nội dung cũ sau cập nhật | Service Worker cũ vẫn đang kiểm soát trang, chưa skip waiting | Dùng self.skipWaiting() trong install event; hoặc gọi clients.claim() trong activate |
| Googlebot không thấy nội dung | Service Worker chặn fetch HTML nhưng không trả response hợp lệ | Luôn kiểm tra event.request.destination === 'document' trước khi cache; không chặn request của bot (có thể kiểm tra user-agent nếu cần) |
Ví dụ thực tế
Một trang tin tức Việt Nam triển khai Service Worker theo chiến lược sau:
- Cache tĩnh: Tất cả file CSS/JS từ
/assets/, hình ảnh logo, favicon — dùngCacheFirstvới thời hạn 30 ngày. - Cache HTML: Chỉ cache
/,/tin-moi/,/chuyen-muc/— không cache bài viết chi tiết (vì thay đổi thường xuyên). - Offline fallback: Khi không kết nối, trả về trang
/offline.htmlvới tiêu đề "Bạn đang offline – vui lòng kiểm tra kết nối" và nút "Thử lại". - Kết quả đo đạc sau 3 tháng: Tỷ lệ thoát giảm 18%, thời gian tải trung bình lần 2 giảm từ 2.4s xuống còn 0.6s, và số lượt xem trang/tuần tăng 12% trên thiết bị di động.
Câu hỏi thường gặp
Service Worker có ảnh hưởng đến việc Googlebot thu thập dữ liệu không?
Không — nếu được viết đúng. Googlebot không chạy Service Worker, nên vẫn tải HTML gốc từ máy chủ. Tuy nhiên, nếu Service Worker chặn hoặc sửa đổi response HTML (ví dụ: trả về nội dung khác cho tất cả request), có thể gây ra sự khác biệt giữa nội dung người dùng thấy và nội dung bot thu thập. Luôn đảm bảo event.request.destination === 'document' được xử lý riêng và không can thiệp vào request từ bot.
Có nên dùng Service Worker cho website WordPress truyền thống?
Có thể — nhưng cần cân nhắc. Nếu site dùng theme tĩnh, plugin nhẹ và không phụ thuộc nhiều vào PHP động, Service Worker giúp tăng tốc đáng kể. Với site có nhiều shortcode, form động hoặc plugin cache phức tạp, cần kiểm tra kỹ tính tương thích. Một số plugin như Super PWA hỗ trợ tích hợp sẵn, nhưng nên test kỹ trên staging trước khi bật live.
Service Worker có làm chậm lần tải đầu tiên không?
Không đáng kể — nếu tối ưu. Việc đăng ký và cài đặt diễn ra song song với tải trang. Thời gian chậm nhất thường dưới 200ms trên mạng 3G. Tuy nhiên, nếu precache quá nhiều file (ví dụ: 500MB ảnh), giai đoạn installing sẽ kéo dài và có thể gây treo tab. Giải pháp: chỉ precache tối đa 10–20 tài nguyên thiết yếu, phần còn lại dùng runtime caching.