`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
,fetch
vepush
gibi 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 Worker
dosyası) 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 isecatch
kullanılabilir. registration.scope
,Service Worker
tarafı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 Worker
tarafı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 Worker
ilk 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});
activate
olayı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.js
algılanır. install
olayı tetiklenir.- Önceki
Service Worker
boşa çıkana kadar beklenir. activate
olayı tetiklenir.- Yeni Service Worker'a geçiş yapılır.
controllerchange
olayı 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});
controllerchange
olayı, 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
controllerchange
olayı 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,
localhost
haricindehttp://
üzerinde çalışmaz. -
Hash'lenmiş Dosya İsimleri Önbellek adı, dosya adı, URL ve sürüm bilgisini içerebilir.
-
İstemcilerle İletişim
Service Worker
ile sayfanın JavaScript'i arasında iletişim kurmak içinpostMessage
kullanı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.