---
title: 'Servis Çalışanları'
source: 'https://academia.sh/tr/kurslar/tarayici-platformu/servis-calisanlari'
course: 'Tarayıcı ve Web Platformu'
language: tr
updated: '2026-08-17T18:09:12+00:00'
license: 'CC BY-SA 4.0'
---

# Servis Çalışanları

Sayfadan bağımsız yaşayan ve isteklere araya girerek yanıt verebilen katman; kapsam kuralı, kurulum–bekleme–etkinleşme döngüsü, istek karşılama sözleşmesi ve yanlış dağıtımın geri alınma yolu.

Buraya kadar kurulan her şey sayfa yüklendikten sonra geçerlidir. Hepsinin öncesinde tek
bir varsayım durur: bileşenin kodu, şablonu ve verisi ağdan gelmiştir. Bağlantı
zayıfladığında bu varsayım düşer ve sayfa, ne kadar iyi kapsüllenmiş olursa olsun, bir hata
ekranına iner. Kuzey Yamaç Ölçüm İstasyonu sayfasının kullanıldığı yer buna elverişli
değildir: ölçüm alan kişi çoğunlukla kapsama alanının kıyısındadır.

Bu ders, sayfanın isteklerini ağa ulaşmadan önce görebilen ve sayfadan bağımsız yaşayan
bir katmanı kurar: **servis çalışanı (service worker)**.

## Sayfadan Bağımsız Bir Bağlam

Servis çalışanı, Web İşçileri dersinde tanıtılan çalışan iş parçacığının bir türüdür ve
onun bütün kısıtlarını taşır: belge ağacına erişimi yoktur, sayfanın değişkenlerini
göremez, sayfayla yalnızca ileti geçirerek konuşur. Üzerine kendi kısıtlarını ekler.

**Bir sayfaya bağlı değildir.** Kaydeden sayfa kapansa da kayıt yerinde kalır; aynı
kökenin başka bir sayfası açıldığında aynı çalışan devreye girer. Bu, onu bir sayfa
bileşeni değil, kökene ait bir hizmet yapar.

**Sürekli çalışmaz.** Tarayıcı çalışanı bir olay geldiğinde uyandırır, iş bitince
sonlandırır. Aradaki süre garanti edilmez. Buradan bağlayıcı bir kural çıkar: **çalışanın
genel kapsamındaki değişkenler kalıcı durum tutamaz.** İki olay arasında kaybolabilirler.
Kalıcı olması gereken her şey depolama katmanına yazılır.

**Yalnızca güvenli bağlamda çalışır.** Kayıt, HTTPS üzerinden sunulan bir **köken (origin)**
gerektirir; geliştirme kolaylığı için geri döngü adresi ayrık tutulmuştur. Gerekçe
doğrudandır: araya giren bir katman, ağı dinleyen birinin eline geçtiğinde sayfanın
tamamını kalıcı olarak değiştirebilir. HTTPS'in Rolü dersindeki bütünlük güvencesi bu
yetkinin önkoşuludur.

## Kapsam ve Denetim

Bir kayıt, kökenin tamamını değil bir yol önekini yönetir. Bu öneke **kapsam (scope)** denir
ve iki ayrı kural onu belirler.

Birincisi bildirimin geçerliliğidir: bir çalışan, betiğinin bulunduğu dizinden daha geniş
bir kapsam bildiremez. `/varlik/js/` altındaki bir betik kökün tamamını yönetemez. Kısıt
aşılabilir, ama yalnızca sunucunun bu izni bir başlıkla vermesiyle — yani dosyayı yükleyen
kişinin değil, sunucuyu yapılandıran kişinin kararıyla.

İkincisi eşlemedir: bir sayfayı, kapsamı o sayfanın yolunun öneki olan kayıtlardan **en
uzunu** denetler. IP Adresi Kavramı dersindeki en uzun önek eşlemesiyle aynı mantıktır.

```js
// kapsam.mjs — kayit kapsaminin en uzun onek kuraliyla eslenmesi
// Kapsam, betigin bulundugu dizinden genis olamaz; genisletmek icin sunucunun
// izin basligi gerekir. Asagidaki iki fonksiyon bu kurallari ayri ayri sinar.

const dizin = (yol) => yol.slice(0, yol.lastIndexOf("/") + 1);

function kapsamGecerliMi(betikYolu, istenenKapsam, izinVerilenUst = null) {
  const enGenis = izinVerilenUst ?? dizin(betikYolu);
  return istenenKapsam.startsWith(enGenis);
}

// Bir sayfayi hangi kayit denetler: kapsami sayfanin yolunun oneki olan
// kayitlardan EN UZUN olani.
function denetleyen(kayitlar, sayfaYolu) {
  const uyanlar = kayitlar.filter((k) => sayfaYolu.startsWith(k.kapsam));
  if (uyanlar.length === 0) return null;
  return uyanlar.reduce((a, b) => (b.kapsam.length > a.kapsam.length ? b : a));
}

const denemeler = [
  { betik: "/sw.js", kapsam: "/" },
  { betik: "/istasyon/sw.js", kapsam: "/istasyon/" },
  { betik: "/istasyon/sw.js", kapsam: "/" },
  { betik: "/istasyon/sw.js", kapsam: "/", izin: "/" },
  { betik: "/varlik/js/sw.js", kapsam: "/istasyon/" },
];

console.log("kapsam bildirimi gecerli mi?");
for (const d of denemeler) {
  const sonuc = kapsamGecerliMi(d.betik, d.kapsam, d.izin);
  console.log(
    `  betik ${d.betik.padEnd(18)} kapsam ${d.kapsam.padEnd(12)}` +
    `${d.izin ? "izin " + d.izin : "izin yok"} → ${sonuc ? "gecerli" : "reddedilir"}`);
}

const kayitlar = [
  { ad: "kok", kapsam: "/" },
  { ad: "istasyon", kapsam: "/istasyon/" },
  { ad: "kuzey-yamac", kapsam: "/istasyon/kuzey-yamac/" },
];

console.log("\nsayfayi hangi kayit denetler?");
for (const sayfa of [
  "/",
  "/hakkinda",
  "/istasyon/",
  "/istasyon/gunluk",
  "/istasyon/kuzey-yamac/olcumler",
]) console.log(`  ${sayfa.padEnd(32)} → ${denetleyen(kayitlar, sayfa)?.ad ?? "(denetimsiz)"}`);
```

```
kapsam bildirimi gecerli mi?
  betik /sw.js             kapsam /           izin yok → gecerli
  betik /istasyon/sw.js    kapsam /istasyon/  izin yok → gecerli
  betik /istasyon/sw.js    kapsam /           izin yok → reddedilir
  betik /istasyon/sw.js    kapsam /           izin / → gecerli
  betik /varlik/js/sw.js   kapsam /istasyon/  izin yok → reddedilir

sayfayi hangi kayit denetler?
  /                                → kok
  /hakkinda                        → kok
  /istasyon/                       → istasyon
  /istasyon/gunluk                 → istasyon
  /istasyon/kuzey-yamac/olcumler   → kuzey-yamac
```

Üçüncü ve dördüncü satırdaki fark, betik yerleşiminin bir dağıtım kararı olduğunu gösterir.
Bir servis çalışanı betiğini varlık dizinine koymak, paketleyicinin çıktısını tek yere
toplamak için doğal görünür ve kapsamı o dizine hapseder. Betiğin kök dizinde durması
teknik bir zorunluluk değil, kapsam bildiriminin bedava geldiği yerdir.

Kapsam eşlemesinin bir sonucu da denetimsiz kalabilmektir: kapsam dışındaki bir sayfa
hiçbir çalışan tarafından görülmez ve ağa doğrudan gider. Kapsam dışı sayfaların
çevrimdışı davranışı yoktur.

## Yaşam Döngüsü ve Bekleme Durumu

Bir servis çalışanı kaydedildiğinde doğrudan işe başlamaz. Aradaki durumlar, aynı sayfada
iki farklı sürümün karışmasını önlemek için vardır.

**Kurulum** yeni sürümün ilk fırsatıdır: ihtiyaç duyacağı kaynakları önceden toplar.
Kurulum başarısız olursa sürüm hiç etkinleşmez ve eski sürüm yerinde kalır — bu, yarım
kalmış bir dağıtımın sayfayı bozmasını önleyen ilk emniyet kilididir.

**Bekleme** kurulumu biten sürümün, eski sürümün denetlediği sayfalar kapanana kadar
beklemesidir. Gerekçesi, bir sayfanın ömrü boyunca tek bir sürümle konuşmasıdır: sayfa
eski sürümün önbelleğine göre yüklenmişken isteklerinin yeni sürüm tarafından
karşılanması, sürüm karışması üretir.

**Etkinleşme** eski sürümün bıraktığı artıkları temizlemek için doğru yerdir; o noktada
eski sürüm hiçbir sayfayı denetlemiyordur.

```js
// calisan-yasam-dongusu.mjs — kurulum, bekleme ve etkinlesme durumlarinin modeli
const izleme = [];

function kayitDefteri() {
  return { etkin: null, bekleyen: null, kurulan: null, denetlenen: new Set() };
}

// Yeni surum kaydedilir: kurulur, sonra ya bekler ya dogrudan etkinlesir.
function kaydet(kayit, surum, { beklemeyiAtla = false } = {}) {
  kayit.kurulan = surum;
  izleme.push(`${surum}: kuruluyor`);
  kayit.kurulan = null;
  const denetlenenVar = kayit.denetlenen.size > 0;
  if (kayit.etkin && denetlenenVar && !beklemeyiAtla) {
    kayit.bekleyen = surum;
    izleme.push(`${surum}: kuruldu → bekliyor (${kayit.etkin} hala ${kayit.denetlenen.size} sayfayi denetliyor)`);
  } else {
    etkinlestir(kayit, surum);
  }
}

function etkinlestir(kayit, surum) {
  if (kayit.etkin) izleme.push(`${kayit.etkin}: artik gecersiz`);
  kayit.etkin = surum;
  kayit.bekleyen = null;
  izleme.push(`${surum}: etkinlesiyor → etkin`);
}

// Denetim yalnizca gezinme aninda kurulur; sahiplenme cagrisi bunu beklemez.
function sayfaAc(kayit, sayfa) {
  kayit.denetlenen.add(sayfa);
  izleme.push(`${sayfa} acildi → denetleyen: ${kayit.etkin ?? "(yok)"}`);
}

function sayfaKapat(kayit, sayfa) {
  kayit.denetlenen.delete(sayfa);
  izleme.push(`${sayfa} kapandi → denetlenen sayfa: ${kayit.denetlenen.size}`);
  if (kayit.bekleyen && kayit.denetlenen.size === 0) etkinlestir(kayit, kayit.bekleyen);
}

console.log("A. Bekleme durumu: eski surum sayfalari birakana kadar bekler");
const a = kayitDefteri();
kaydet(a, "s1");
sayfaAc(a, "olcumler");
kaydet(a, "s2");
sayfaAc(a, "gunluk");
sayfaKapat(a, "olcumler");
sayfaKapat(a, "gunluk");
console.log(izleme.map((s) => "  " + s).join("\n"));

izleme.length = 0;
console.log("\nB. Beklemeyi atlama: yeni surum acik sayfalari devralir");
const b = kayitDefteri();
kaydet(b, "s1");
sayfaAc(b, "olcumler");
kaydet(b, "s2", { beklemeyiAtla: true });
console.log(izleme.map((s) => "  " + s).join("\n"));
console.log(`  → 'olcumler' sayfasi s1 ile yuklendi, isteklerini artik ${b.etkin} karsiliyor`);
```

```
A. Bekleme durumu: eski surum sayfalari birakana kadar bekler
  s1: kuruluyor
  s1: etkinlesiyor → etkin
  olcumler acildi → denetleyen: s1
  s2: kuruluyor
  s2: kuruldu → bekliyor (s1 hala 1 sayfayi denetliyor)
  gunluk acildi → denetleyen: s1
  olcumler kapandi → denetlenen sayfa: 1
  gunluk kapandi → denetlenen sayfa: 0
  s1: artik gecersiz
  s2: etkinlesiyor → etkin

B. Beklemeyi atlama: yeni surum acik sayfalari devralir
  s1: kuruluyor
  s1: etkinlesiyor → etkin
  olcumler acildi → denetleyen: s1
  s2: kuruluyor
  s1: artik gecersiz
  s2: etkinlesiyor → etkin
  → 'olcumler' sayfasi s1 ile yuklendi, isteklerini artik s2 karsiliyor
```

Birinci bölümün altıncı satırı sık gözden kaçan davranıştır: `s2` beklerken açılan yeni
sayfa da `s1` tarafından denetlenir. Bekleme durumunu bitiren şey sekmenin yenilenmesi
değil, kökene ait **bütün** sayfaların kapanmasıdır. Sekmeyi yenilemek eski sayfayı
kapatmadan yenisini açtığı için beklemeyi çoğu zaman bitirmez.

İkinci bölüm beklemeyi atlamanın ne yaptığını ve neyi riske attığını gösterir. Yeni sürüm
hemen etkinleşir ve açık sayfaları devralır. Kazanç dağıtımın anında yayılmasıdır; bedel,
eski sürümle yüklenmiş bir sayfanın isteklerinin yeni sürüm tarafından karşılanmasıdır.
Sayfanın kodu ile çalışanın beklentisi ayrıştığında bu kırılma üretir. Beklemeyi atlamak,
sürümler arası uyumun sağlandığı bilinen dağıtımlarda güvenlidir; her dağıtımda uygulanan
varsayılan bir alışkanlık değildir.

Kaydın güncellenmesi ayrı bir denetimdir: tarayıcı çalışan betiğini belirli aralıklarla
yeniden ister ve gelen içerik öncekinden **bayt düzeyinde** farklıysa yeni sürüm sayar. Bu
yüzden çalışan betiğinin kendisi uzun ömürlü olarak önbelleklenmemelidir; aksi hâlde
güncelleme denetimi eski kopyayı okur ve dağıtım hiç görülmez.

## İstekleri Araya Girerek Karşılamak

Etkin bir çalışan, denetlediği sayfaların ürettiği her ağ isteği için bir olay alır: sayfa
gezinmeleri, betikler, biçem dosyaları, görseller, veri istekleri. Olay nesnesi isteği
taşır; çalışan iki şeyden birini yapar.

**Yanıt vermezse** istek olağan yoluna devam eder ve ağa gider. Bu, hiçbir şey yapmamanın
güvenli varsayılan olduğu anlamına gelir.

**Yanıt verirse** ağ hiç kullanılmayabilir. Yanıt bir söz olarak bildirilir; söz çözülene
kadar istek bekler. Sözleşmenin katı bir kısıtı vardır: yanıt verme kararı olay
geri çağrısı çalışırken **eşzamanlı** olarak bildirilmelidir. Karar bir söz beklendikten
sonra verilirse geç kalınmış olur; tarayıcı bu arada isteği ağa yollamıştır. Yanıtı üretmek
eşzamansız olabilir, yanıt vereceğini bildirmek olamaz.

İki ayrıntı sık atlanır. Birincisi, yanıt gövdesi **bir kez okunur**; hem önbelleğe yazıp
hem sayfaya verilmesi gerekiyorsa kopyalanmalıdır. İkincisi, başka bir kökenden gelen ve
başlıkları paylaşıma kapalı olan yanıtlar **saydam değildir**: durum kodu okunamaz, içeriği
incelenemez, boyutu belirsizdir. Böyle bir yanıtın başarılı olup olmadığı anlaşılamadığı
için önbelleğe yazılması, hata sayfasının kalıcılaşmasına yol açabilir.

Çalışanın göremediği istekler de vardır: kapsam dışındaki sayfaların istekleri, başka
kökenlerin sayfalarından doğan istekler ve çalışanın kendi betiğinin güncelleme isteği.

## Dağıtımın Geri Alınamazlığı

Servis çalışanı, sunucuya değil kullanıcının aygıtına dağıtılan bir vekildir. Bozuk bir
sürüm sunucudan silinmekle ortadan kalkmaz; kullanıcının aygıtında etkin kalır ve sayfayı
kendi bildiği hâline sabitler. Sunucudaki düzeltme, çalışan güncelleme denetimini yapıp
yeni betiği kabul edene kadar kullanıcıya ulaşmaz.

Bunun karşılığı iki alışkanlıktır. Birincisi, çalışan betiğinin kısa ömürlü
önbelleklenmesi — güncelleme denetiminin gerçekten ağa çıkması. İkincisi, kaydı silen ve
önbellekleri boşaltan **asgari bir sürümün** hazır tutulması: ne yaptığı belirsiz bir
çalışanı devreden çıkarmanın tek yolu, onun yerine kendini kaldıran bir çalışan
dağıtmaktır.

## Özet

- Servis çalışanı sayfaya değil kökene bağlıdır, olaylar arasında sonlandırılabilir ve
  genel kapsamında kalıcı durum tutamaz.
- Kapsam iki kuralla belirlenir: betiğin dizininden geniş olamaz, ve bir sayfayı öneki
  eşleşen kayıtlardan en uzunu denetler.
- Kurulum başarısız olursa sürüm etkinleşmez; bekleme durumu, bir sayfanın ömrü boyunca
  tek sürümle konuşmasını sağlar ve kökenin bütün sayfaları kapanana kadar sürer.
- Beklemeyi atlamak dağıtımı anında yayar, ama eski sayfayı yeni sürümle eşleştirir; sürüm
  uyumu bilinmeden yapılmaz.
- İstek karşılama kararı eşzamanlı bildirilmelidir; yanıt gövdesi bir kez okunur ve saydam
  olmayan yanıtların başarısı denetlenemez.
- Çalışan kullanıcının aygıtına dağıtılan bir vekildir; bozuk sürümü geri almanın yolu,
  kendini kaldıran bir sürüm dağıtmaktır.

## Sonraki Adım

Bu ders araya girme yetkisini kurdu ama onunla ne yapılacağını açık bıraktı. İsteği
karşılamanın tek bir doğru biçimi yoktur: istasyonun logosu ile ölçüm listesi aynı kuralla
sunulamaz. Biri değişmez ve ağdan sorulması gereksizdir; diğeri dakikada bir değişir ve
eski kopyası yanıltıcıdır. Aradaki seçim, hız ile tazelik arasında bilinçli bir ödünleşimdir
ve her kaynak türü için ayrı verilir. Sonraki ders bu kararı, önbellek anahtarının nasıl
üretildiği ve bir kopyanın ne zaman taze sayıldığı sorularıyla birlikte ele alır.
