`Service Worker` JavaScript'te

`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 &amp; 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 ve push 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 (yani Service Worker dosyası) kaydı için navigator.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 ise catch 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 sayfalar Service 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:.

  1. Yeni bir sw.js algılanır.
  2. install olayı tetiklenir.
  3. Önceki Service Worker boşa çıkana kadar beklenir.
  4. activate olayı tetiklenir.
  5. Yeni Service Worker'a geçiş yapılır.
  6. 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 haricinde http:// ü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çin postMessage 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.

YouTube Video