`Service Worker` di JavaScript
Artikel ini menjelaskan konsep Service Worker
di JavaScript.
Kami akan menjelaskan langkah demi langkah mulai dari dasar-dasar Service Worker
hingga kontrol cache secara praktis.
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
di JavaScript
Service Worker
adalah fitur JavaScript yang berada di antara browser dan jaringan, memungkinkan caching permintaan dan dukungan offline. Ini adalah teknologi inti dari PWA (Progressive Web Apps) dan memberikan pengalaman seperti aplikasi native pada aplikasi web.
Apa itu Service Worker
?
Service Worker
adalah file JavaScript yang dijalankan di background thread pada browser. Ia berjalan pada thread terpisah dari halaman, tidak dapat mengakses UI, tetapi dapat mencegat permintaan jaringan, mengelola cache, dan menangani push notification.
Fitur utama dari Service Worker
meliputi hal-hal berikut:.
- Hanya bekerja melalui HTTPS, kecuali di localhost.
- Menggunakan API asynchronous berbasis Promise.
- Berbasis event, menggunakan event seperti
install
,activate
,fetch
, danpush
.
Mendaftarkan Service Worker
Pertama, mari kita tulis kode untuk mendaftarkan Service Worker
di browser.
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
(fileService Worker
). - Anda dapat menggunakan
then
untuk menangani keberhasilan dancatch
untuk menangani kesalahan saat pendaftaran. registration.scope
mewakili rentang path (cakupan) yang dipengaruhi olehService Worker
.- Secara default, cakupannya adalah direktori tempat file yang didaftarkan (dalam hal ini,
/sw.js
) berada dan subdirektorinya.
Cakupan Service Worker
Jika Anda ingin membatasi cakupannya, Anda dapat menentukan scope
menggunakan argumen kedua dari 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 pengaturan ini, hanya halaman di bawah
/app/
yang akan dikendalikan olehService Worker
.
Membuat file Service Worker
Selanjutnya, buat file bernama sw.js
dan implementasikan event-event dasar.
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];
Kode ini mendefinisikan daftar sumber daya yang akan di-cache.
Peran dan mekanisme masing-masing event
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')
dipicu ketikaService Worker
didaftarkan untuk pertama kalinya. Pada tahap ini, file-file yang diperlukan akan di-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});
- Pada event
activate
, cache lama akan dihapus untuk mengoptimalkan penyimpanan. Hanya cache dari versi terbaru yang disimpan.
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 dicegat—jika ada versi yang sudah di-cache, itu akan dikembalikan; jika tidak ada, diambil dari jaringan. Ketika offline, halaman alternatif (misal, offline.html
) akan dikembalikan.
Mengonfirmasi operasi
Mari kita periksa bagaimana cara kerja Service Worker
.
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 memeriksa pendaftaran
Service Worker
dan perilaku pengambilan sumber daya dengan mengklik tombol uji.
Contoh Strategi Caching
Berikut adalah strategi caching yang umum:.
Cache First
Berikut contoh implementasi untuk strategi 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});
- Kode ini menerapkan strategi cache-first, di mana sumber daya yang diminta akan dikembalikan dari cache jika tersedia; jika tidak, akan diambil dari jaringan.
Network First
Berikut contoh implementasi untuk strategi 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});
- Kode ini menerapkan strategi network-first, di mana sumber daya yang diminta diambil terlebih dahulu dari jaringan, dan jika gagal, akan diambil dari cache.
Cache hanya file gaya dan JavaScript, akses API secara real-time
Berikut adalah contoh implementasi di mana file gaya dan JavaScript di-cache, sementara API diakses secara real-time:.
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});
- Kode ini selalu mengakses permintaan API secara real-time dan menerapkan strategi cache-first untuk file statis seperti stylesheet dan JavaScript.
Alur pembaruan
Alur pembaruan Service Worker adalah sebagai berikut:.
sw.js
baru terdeteksi.- Event
install
dijalankan. - Menunggu hingga
Service Worker
sebelumnya tidak aktif. - Event
activate
dijalankan. - Beralih ke Service Worker yang baru.
- Event
controllerchange
dijalankan.
Deteksi pembaruan
Setelah Service Worker
terpasang, versi lama akan tetap digunakan sampai kunjungan berikutnya. Untuk menerapkan pembaruan, biasanya digunakan kode yang mendeteksi pembaruan dan memuat ulang halaman.
1navigator.serviceWorker.addEventListener('controllerchange', () => {
2 window.location.reload();
3});
- Event
controllerchange
dijalankan ketika pengendali Service Worker, yaitu Service Worker yang mengendalikan halaman saat ini, berubah. - Halaman yang sudah terbuka akan tetap menggunakan Service Worker saat ini, dan Service Worker yang baru dipasang tidak langsung berlaku di halaman-halaman tersebut. Oleh karena itu, digunakan teknik di mana event
controllerchange
digunakan untuk mendeteksi bahwa pengendali baru telah aktif, kemudian halaman dimuat ulang agar pembaruan segera diterapkan.
Peringatan dan Praktik Terbaik
Saat menggunakan Service Worker
, perhatikan hal-hal berikut:.
-
HTTPS Diperlukan Karena batasan keamanan, tidak akan bekerja pada
http://
kecuali dilocalhost
. -
Nama File dengan Hash Nama cache dapat mencakup nama file, URL, dan informasi versi.
-
Komunikasi dengan Klien Gunakan
postMessage
untuk berkomunikasi antaraService Worker
dan JavaScript halaman.
Ringkasan
Service Worker
adalah teknologi penting untuk dukungan offline dan peningkatan performa pada aplikasi web. Dengan memahami alur dasar instalasi, aktivasi, dan penanganan fetch, serta menerapkan strategi caching yang tepat, Anda dapat membangun aplikasi web dengan kualitas lebih tinggi.
Anda dapat mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Silakan periksa juga saluran YouTube kami.