`Service Worker` dalam JavaScript
Artikel ini menerangkan konsep Service Worker
dalam JavaScript.
Kami akan menerangkan secara langkah demi langkah dari asas Service Worker
hingga kawalan cache secara praktikal.
YouTube Video
offline.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>Offline</title>
6</head>
7<body>
8 <h1>You are offline</h1>
9 <p>This is the offline fallback page.</p>
10</body>
11</html>
style.css
1body {
2 font-family: sans-serif;
3 background-color: #f0f0f0;
4 padding: 20px;
5}
6h1 {
7 color: #333;
8}
javascript-service-worker.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>JavaScript & HTML</title>
6 <style>
7 * {
8 box-sizing: border-box;
9 }
10
11 body {
12 margin: 0;
13 padding: 1em;
14 padding-bottom: 10em;
15 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16 background-color: #f7f9fc;
17 color: #333;
18 line-height: 1.6;
19 }
20
21 .container {
22 max-width: 800px;
23 margin: 0 auto;
24 padding: 1em;
25 background-color: #ffffff;
26 border: 1px solid #ccc;
27 border-radius: 10px;
28 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
29 }
30
31 .container-flex {
32 display: flex;
33 flex-wrap: wrap;
34 gap: 2em;
35 max-width: 1000px;
36 margin: 0 auto;
37 padding: 1em;
38 background-color: #ffffff;
39 border: 1px solid #ccc;
40 border-radius: 10px;
41 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
42 }
43
44 .left-column, .right-column {
45 flex: 1 1 200px;
46 min-width: 200px;
47 }
48
49 h1, h2 {
50 font-size: 1.2rem;
51 color: #007bff;
52 margin-top: 0.5em;
53 margin-bottom: 0.5em;
54 border-left: 5px solid #007bff;
55 padding-left: 0.6em;
56 background-color: #e9f2ff;
57 }
58
59 button {
60 display: block;
61 margin: 1em auto;
62 padding: 0.75em 1.5em;
63 font-size: 1rem;
64 background-color: #007bff;
65 color: white;
66 border: none;
67 border-radius: 6px;
68 cursor: pointer;
69 transition: background-color 0.3s ease;
70 }
71
72 button:hover {
73 background-color: #0056b3;
74 }
75
76 #output {
77 margin-top: 1em;
78 background-color: #1e1e1e;
79 color: #0f0;
80 padding: 1em;
81 border-radius: 8px;
82 min-height: 200px;
83 font-family: Consolas, monospace;
84 font-size: 0.95rem;
85 overflow-y: auto;
86 white-space: pre-wrap;
87 }
88
89 .highlight {
90 outline: 3px solid #ffc107; /* yellow border */
91 background-color: #fff8e1; /* soft yellow background */
92 transition: background-color 0.3s ease, outline 0.3s ease;
93 }
94
95 .active {
96 background-color: #28a745; /* green background */
97 color: #fff;
98 box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
99 transition: background-color 0.3s ease, box-shadow 0.3s ease;
100 }
101 </style>
102</head>
103<body>
104 <div class="container">
105 <h1>JavaScript Console</h1>
106 <button id="executeBtn">Execute</button>
107 <div id="output"></div>
108 </div>
109
110 <div class="container">
111 <h2>HTML Sample</h2>
112 <button id="fetchBtn">Fetch Test</button>
113 </div>
114
115 <script>
116 // Override console.log to display messages in the #output element
117 (function () {
118 // Override console.log
119 const originalLog = console.log;
120 console.log = function (...args) {
121 originalLog.apply(console, args);
122 const message = document.createElement('div');
123 message.textContent = args.map(String).join(' ');
124 output.appendChild(message);
125 };
126
127 // Override console.error
128 const originalError = console.error;
129 console.error = function (...args) {
130 originalError.apply(console, args);
131 const message = document.createElement('div');
132 message.textContent = args.map(String).join(' ');
133 message.style.color = 'red'; // Color error messages red
134 output.appendChild(message);
135 };
136 })();
137
138 document.getElementById('executeBtn').addEventListener('click', () => {
139 // Prevent multiple loads
140 if (document.getElementById('externalScript')) return;
141
142 const script = document.createElement('script');
143 script.src = 'javascript-service-worker.js';
144 script.id = 'externalScript';
145 //script.onload = () => console.log('javascript-service-worker.js loaded and executed.');
146 //script.onerror = () => console.log('Failed to load javascript-service-worker.js.');
147 document.body.appendChild(script);
148 });
149 </script>
150</body>
151</html>
Service Worker
dalam JavaScript
Service Worker
ialah ciri dalam JavaScript yang berada di antara pelayar web dan rangkaian, membolehkan caching permintaan serta sokongan luar talian. Ia merupakan teknologi teras bagi PWA (Progressive Web Apps) dan memberikan pengalaman seperti aplikasi asli kepada aplikasi web.
Apakah itu Service Worker
?
Service Worker
ialah fail JavaScript yang dijalankan di thread latar belakang pelayar web. Ia berjalan di thread yang berasingan daripada halaman, tidak boleh mengakses UI, tetapi boleh memintas permintaan rangkaian, mengurus cache, dan mengendalikan notifikasi push.
Ciri utama Service Worker
termasuk yang berikut:.
- Ia hanya berfungsi melalui HTTPS, kecuali di localhost.
- Ia menggunakan API asynchronous berasaskan Promise.
- Ia dipacu oleh peristiwa (event-driven), menggunakan peristiwa seperti
install
,activate
,fetch
, danpush
.
Mendaftar Service Worker
Pertama sekali, mari kita tulis kod untuk mendaftarkan Service Worker
dalam pelayar web.
1if ('serviceWorker' in navigator) {
2 window.addEventListener('load', () => {
3 navigator.serviceWorker.register('/sw.js')
4 .then(registration => {
5 console.log(
6 'Service Worker registered with scope:',
7 registration.scope
8 );
9 })
10 .catch(error => {
11 console.error('Service Worker registration failed:', error);
12 });
13 });
14}
Penjelasan
- Gunakan
navigator.serviceWorker.register()
untuk mendaftarkan/sw.js
(failService Worker
). - Anda boleh menggunakan
then
untuk pengendalian kejayaan dancatch
untuk pengendalian ralat semasa pendaftaran. registration.scope
mewakili julat laluan (skop) yang terjejas olehService Worker
.- Secara lalai, skop adalah direktori di mana fail yang didaftarkan (dalam kes ini,
/sw.js
) terletak dan subdirektorinya.
Skop Service Worker
Jika anda ingin mengehadkan skop, anda boleh menentukan scope
menggunakan argumen kedua pada register
.
1navigator.serviceWorker.register('/sw.js', { scope: '/app/' })
2.then(registration => {
3 console.log(
4 'Service Worker registered with scope:',
5 registration.scope
6 );
7});
Penjelasan
- Dengan tetapan ini, hanya halaman di bawah
/app/
akan dikawal olehService Worker
.
Mencipta fail Service Worker
Seterusnya, cipta fail bernama sw.js
dan laksanakan peristiwa-peristiwa asas.
1// sw.js
2const CACHE_NAME = 'my-cache-v1';
3const urlsToCache = [
4 '/',
5 '/index.html',
6 '/styles.css',
7 '/script.js',
8 '/offline.html'
9];
Kod ini mentakrifkan senarai sumber yang akan disimpan dalam cache.
Peranan dan mekanisme bagi setiap peristiwa
install
1// Install event (initial caching)
2self.addEventListener('install', event => {
3 console.log('[ServiceWorker] Install');
4 event.waitUntil(
5 caches.open(CACHE_NAME).then(cache => {
6 console.log('[ServiceWorker] Caching app shell');
7 return cache.addAll(urlsToCache);
8 })
9 );
10});
self.addEventListener('install')
dicetuskan apabilaService Worker
didaftarkan buat kali pertama. Pada peringkat ini, fail-fail yang diperlukan akan dimasukkan ke dalam cache terlebih dahulu.
activate
1// Activation event (delete old caches)
2self.addEventListener('activate', event => {
3 console.log('[ServiceWorker] Activate');
4 event.waitUntil(
5 caches.keys().then(keyList => {
6 return Promise.all(keyList.map(key => {
7 if (key !== CACHE_NAME) {
8 console.log('[ServiceWorker] Removing old cache:', key);
9 return caches.delete(key);
10 }
11 }));
12 })
13 );
14 return self.clients.claim();
15});
- Dalam peristiwa
activate
, cache lama akan dipadam untuk mengoptimumkan storan. Hanya cache versi baharu yang dikekalkan.
fetch
1// Fetch event (cache-first strategy)
2self.addEventListener('fetch', event => {
3 console.log('[ServiceWorker] Fetch', event.request.url);
4 event.respondWith(
5 caches.match(event.request).then(response => {
6 return response || fetch(event.request).catch(() => caches.match('/offline.html'));
7 })
8 );
9});
Semua permintaan HTTP akan dipintas—jika versi yang telah dicache wujud, ia akan dipulangkan; jika tidak, ia diambil dari rangkaian. Apabila luar talian, halaman alternatif (contohnya, offline.html
) akan dipulangkan.
Mengesahkan operasi
Mari kita lihat dengan lebih lanjut bagaimana Service Worker
berfungsi.
1document.getElementById('fetchBtn').addEventListener('click', () => {
2 fetch('/style.css')
3 .then(response => response.text())
4 .then(data => {
5 console.log('Fetched data:', data);
6 })
7 .catch(error => {
8 console.error('Fetch failed:', error);
9 });
10});
- Di sini, kita menyemak pendaftaran
Service Worker
dan tingkah laku mendapatkan sumber dengan menekan butang uji.
Contoh Strategi Caching
Berikut ialah strategi caching yang biasa digunakan:.
Cache Diutamakan (Cache First)
Berikut adalah contoh pelaksanaan untuk strategi Cache Diutamakan (Cache First):.
1self.addEventListener('fetch', event => {
2 event.respondWith(
3 caches.match(event.request).then(response => {
4 return response || fetch(event.request);
5 })
6 );
7});
- Kod ini melaksanakan strategi cache-first, di mana sumber yang diminta akan dikembalikan dari cache jika tersedia; jika tidak, ia akan dimuat turun dari rangkaian.
Rangkaian Diutamakan (Network First)
Berikut adalah contoh pelaksanaan untuk strategi Rangkaian Diutamakan (Network First):.
1self.addEventListener('fetch', event => {
2 event.respondWith(
3 fetch(event.request)
4 .then(response => {
5 return caches.open(CACHE_NAME).then(cache => {
6 cache.put(event.request, response.clone());
7 return response;
8 });
9 })
10 .catch(() => caches.match(event.request))
11 );
12});
- Kod ini melaksanakan strategi network-first, di mana sumber yang diminta akan dimuat turun dari rangkaian terlebih dahulu, dan jika gagal, ia akan diambil dari cache.
Cache hanya gaya dan JavaScript, akses API secara masa nyata
Berikut adalah contoh pelaksanaan di mana gaya dan JavaScript dicache tetapi API diakses secara masa nyata:.
1self.addEventListener('fetch', event => {
2 if (event.request.url.includes('/api/')) {
3 // Fetch API responses in real-time without caching
4 return;
5 }
6
7 // Use cache-first strategy for static files
8 event.respondWith(
9 caches.match(event.request).then(response => {
10 return response || fetch(event.request);
11 })
12 );
13});
- Kod ini sentiasa mengakses permintaan API secara masa nyata dan mengaplikasikan strategi cache-first pada fail statik seperti stylesheet dan JavaScript.
Aliran kemas kini
Aliran kemas kini untuk Service Worker adalah seperti berikut:.
sw.js
yang baharu dikesan.- Peristiwa
install
dicetuskan. - Ia menunggu sehingga
Service Worker
sebelum ini tidak lagi aktif. - Peristiwa
activate
dicetuskan. - Ia bertukar kepada Service Worker yang baharu.
- Acara
controllerchange
dicetuskan.
Pengesanan kemas kini
Setelah Service Worker
dipasang, yang lama akan terus digunakan sehingga lawatan seterusnya. Untuk melaksanakan kemas kini, adalah biasa untuk menggunakan kod yang mengesan kemas kini dan memuat semula halaman.
1navigator.serviceWorker.addEventListener('controllerchange', () => {
2 window.location.reload();
3});
- Acara
controllerchange
dicetuskan apabila pengawal Service Worker, iaitu Service Worker yang mengawal halaman semasa, berubah. - Halaman yang sudah dibuka akan kekal menggunakan Service Worker semasa, dan Service Worker yang baru dipasang tidak akan berkuat kuasa serta-merta pada halaman tersebut. Oleh itu, satu teknik digunakan di mana acara
controllerchange
digunakan untuk mengesan bahawa pengawal baharu telah aktif, kemudian halaman dimuat semula untuk melaksanakan kemas kini dengan segera.
Langkah Berhati-hati dan Amalan Terbaik
Apabila menggunakan Service Worker
, sila ambil perhatian perkara berikut:.
-
HTTPS Diperlukan Disebabkan sekatan keselamatan, ia tidak berfungsi melalui
http://
kecuali padalocalhost
. -
Nama Fail Bertanda Hash Nama cache boleh mengandungi nama fail, URL, dan maklumat versi.
-
Komunikasi dengan Klien Gunakan
postMessage
untuk berkomunikasi antaraService Worker
dan JavaScript halaman.
Ringkasan
Service Worker
ialah teknologi penting untuk sokongan luar talian dan penambahbaikan prestasi dalam aplikasi web. Dengan memahami aliran asas pemasangan, pengaktifan dan pengendalian fetch, serta melaksanakan strategi caching yang sesuai, anda boleh membina aplikasi web yang lebih berkualiti tinggi.
Anda boleh mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Sila lihat juga saluran YouTube kami.