`Service Worker` JavaScript'te
Bu makale, JavaScript'te Service Worker kavramını açıklamaktadır.
Service Worker'ın temellerinden pratik önbellek kontrolüne kadar adım adım açıklayacağız.
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 JavaScript'te
Service Worker, tarayıcı ile ağ arasında duran ve istek önbellekleme ile çevrimdışı desteğini sağlayan bir JavaScript özelliğidir. Bu, PWAs (Progressive Web Apps) için temel bir teknolojidir ve web uygulamalarına yerel uygulama benzeri bir deneyim kazandırır.
Service Worker nedir?
Service Worker, tarayıcının arka plan iş parçacığında çalışan bir JavaScript dosyasıdır. Sayfadan ayrı bir iş parçacığında çalışır, kullanıcı arayüzüne erişemez fakat ağ isteklerini yakalayabilir, önbelleği yönetebilir ve anlık bildirimleri işleyebilir.
Service Worker'ın temel özellikleri şunlardır:.
- Sadece HTTPS ile çalışır, localhost hariç.
- Promise tabanlı asenkron bir API kullanır.
- Olay tabanlıdır,
install,activate,fetchvepushgibi olayları kullanır.
Service Worker Kaydı
Öncelikle, tarayıcıda bir Service Worker kaydetmek için kodu yazalım.
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}Açıklama
/sw.js(yaniService Workerdosyası) kaydı içinnavigator.serviceWorker.register()kullanılmalıdır.- Kayıt sırasında başarı durumunu yönetmek için
then, hata durumunu yönetmek için isecatchkullanılabilir. registration.scope,Service Workertarafından etkilenen yol aralığını (kapsamı) temsil eder.- Varsayılan olarak kapsam, kaydedilen dosyanın (bu durumda
/sw.js) bulunduğu dizin ve onun alt dizinleridir.
Service Worker Kapsamı
Kapsamı sınırlandırmak istiyorsanız, register fonksiyonunun ikinci argümanını kullanarak scope belirtebilirsiniz.
1navigator.serviceWorker.register('/sw.js', { scope: '/app/' })
2.then(registration => {
3 console.log(
4 'Service Worker registered with scope:',
5 registration.scope
6 );
7});Açıklama
- Bu ayar ile sadece
/app/altındaki sayfalarService Workertarafından kontrol edilecektir.
Service Worker dosyasını oluşturmak
Daha sonra, sw.js adında bir dosya oluşturup temel olayları uygulayın.
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];Bu kod, önbelleğe alınacak kaynakların bir listesini tanımlar.
Her olayın rolleri ve işleyiş mekanizması
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'),Service Workerilk kez kaydedildiğinde tetiklenir. Bu aşamada, gerekli dosyalar önbelleğe alınır.
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});activateolayında, depolama alanını optimize etmek için eski önbellekler silinir. Sadece yeni sürüme ait önbellek tutulur.
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});Tüm HTTP istekleri yakalanır—eğer önbellekte bir sürüm varsa döndürülür, yoksa ağdan alınır. Çevrimdışı olduğunda, alternatif bir sayfa (örneğin, offline.html) döndürülür.
İşlemi onaylama
Hadi şimdi Service Worker'ın nasıl çalıştığını gerçekten inceleyelim.
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});- Burada,
Service Worker'ın kaydını ve test düğmesine tıklayarak kaynakların getirilme davranışını kontrol ediyoruz.
Önbellekleme Stratejilerine Örnekler
Aşağıdakiler yaygın önbellekleme stratejileridir:.
Önce Önbellek
Cache First (Önce Önbellek) stratejisine örnek bir uygulama:.
1self.addEventListener('fetch', event => {
2 event.respondWith(
3 caches.match(event.request).then(response => {
4 return response || fetch(event.request);
5 })
6 );
7});- Bu kod, önbellek öncelikli bir strateji uygular; istenen kaynak önbellekte varsa oradan döndürülür, yoksa ağdan getirilir.
Önce Ağ
Network First (Önce Ağ) stratejisine örnek bir uygulama:.
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});- Bu kod, ağ öncelikli bir strateji uygular; istenen kaynak önce ağdan alınır, başarısız olursa önbellekten alınır.
Sadece stil ve JavaScript dosyalarını önbelleğe al, API'lere gerçek zamanlı eriş
Stil ve JavaScript dosyalarının önbelleğe alındığı, API'lere ise gerçek zamanlı erişilen örnek bir uygulama:.
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});- Bu kod, API isteklerine her zaman gerçek zamanlı olarak erişir ve stil dosyaları veya JavaScript gibi statik dosyalarda önbellek öncelikli strateji uygular.
Güncelleme akışı
Bir Service Worker'ın güncelleme akışı aşağıdaki gibidir:.
- Yeni bir
sw.jsalgılanır. installolayı tetiklenir.- Önceki
Service Workerboşa çıkana kadar beklenir. activateolayı tetiklenir.- Yeni Service Worker'a geçiş yapılır.
controllerchangeolayı tetiklenir.
Güncelleme tespiti
Bir Service Worker yüklendikten sonra, eski olanı bir sonraki ziyarete kadar kullanılmaya devam edilir. Güncellemeleri uygulamak için, güncellemeleri algılayan ve sayfayı yeniden yükleyen kodun kullanılması yaygındır.
1navigator.serviceWorker.addEventListener('controllerchange', () => {
2 window.location.reload();
3});controllerchangeolayı, Service Worker'ın denetleyicisi - yani mevcut sayfayı kontrol eden Service Worker - değiştiğinde tetiklenir.- Halihazırda açık olan sayfalar mevcut Service Worker'ı kullanmaya devam eder ve yeni yüklenen Service Worker bu sayfalarda hemen etkili olmaz. Bu nedenle, yeni bir denetleyicinin etkinleştiğini algılamak için
controllerchangeolayı kullanılır ve ardından sayfayı hemen yeniden yükleyerek güncelleme uygulanır.
Uyarılar ve En İyi Uygulamalar
Service Worker kullanırken aşağıdaki noktalara dikkat edin:.
-
HTTPS Gerekli Güvenlik kısıtlamaları nedeniyle,
localhostharicindehttp://üzerinde çalışmaz. -
Hash'lenmiş Dosya İsimleri Önbellek adı, dosya adı, URL ve sürüm bilgisini içerebilir.
-
İstemcilerle İletişim
Service Workerile sayfanın JavaScript'i arasında iletişim kurmak içinpostMessagekullanın.
Özet
Service Worker, web uygulamalarında çevrimdışı destek ve performans arttırımı için vazgeçilmez bir teknolojidir. Kurulum, etkinleştirme ve fetch işlemi temel akışını anlayıp, uygun önbellekleme stratejileri ile uygulayarak daha yüksek kaliteli web uygulamaları geliştirebilirsiniz.
Yukarıdaki makaleyi, YouTube kanalımızda Visual Studio Code'u kullanarak takip edebilirsiniz. Lütfen YouTube kanalını da kontrol edin.