---
title: 'Yan Etkiler'
source: 'https://academia.sh/tr/kurslar/bilesen-tabanli-gelistirme/yan-etkiler'
course: 'Bileşen Tabanlı Arayüz Geliştirme'
language: tr
updated: '2026-08-17T18:09:13+00:00'
license: 'CC BY-SA 4.0'
---

# Yan Etkiler

Bileşenin dış dünyayla eşzamanlanması; oluşturmanın saflığı, yan etki kaydının belgeye yazma aşamasından sonra çalışması, bağımlılık listesinin karşılaştırılması, temizleme işlevinin sırası ve eşzamansız etkilerde yarış koşulu.

Önceki ders bileşen gövdesinin tek bir işi olduğunu kurdu: durumdan ve girdilerden bir
çıktı hesaplamak. Ölçüm istasyonu sayfasının yapması gereken işlerin bir bölümü bu hesabın
dışında kalır. Sunucudan ölçüm çekmek, ölçüm akışına abone olmak, seçili süzgeci yerel
depolamaya yazmak, belge başlığını değiştirmek, bir zamanlayıcı kurmak — hiçbiri bir çıktı
hesabı değildir. Bunlar programın dışarıya dokunduğu noktalardır ve Programlama Temelleri
kursunda tanıtılan adla **yan etki (side effect)** taşırlar.

Bu derste sorulan soru, bu işlerin nereye yazılacağıdır. Yanıt bir kayıt mekanizmasıdır:
gövde yan etkiyi yapmaz, yapılacak işi bildirir. Çalışma zamanı bu bildirimi alır, doğru
anda çalıştırır ve — bu dersin en çok atlanan yarısı — kurulan şeyi doğru anda söker.

## Oluşturmanın Saflığı

Yan etkinin gövdeye yazılamamasının üç ayrı gerekçesi vardır ve üçü de gövdenin bir
sözleşmeye bağlı olmasından gelir: aynı girdilerle çağrılan gövde aynı çıktıyı üretmeli ve
başka hiçbir şey yapmamalıdır.

Birincisi zamanlamadır. Gövdenin ürettiği ağaç henüz belgeye yazılmamıştır; uzlaşma
sonucundaki fark daha uygulanmamıştır. Gövde içinde bir düğümü ölçmeye ya da odaklamaya
çalışan kod, olmayan bir düğümle konuşur.

İkincisi iptal edilebilirliktir. Bir oluşturma yarıda kesilebilir; çalışma zamanı daha
öncelikli bir güncelleme gelince başlanmış hesabı bırakıp baştan başlayabilir. Gövde
içinde gönderilen bir istek, sonucu hiç kullanılmayacak bir istektir; gövde içinde artan
bir sayaç iki kez artmış olabilir.

Üçüncüsü çoğaltmadır. Aynı gövde, geliştirme sırasındaki denetimler ya da bir sunucu
tarafı oluşturma turu nedeniyle iki kez çalıştırılabilir. Saf bir gövde için bu görünmez
bir işlemdir; abonelik açan bir gövde için iki aboneliktir.

Bu üç gerekçe tek bir kurala iner: **gövde okur ve hesaplar; dışarıya dokunan her iş
kayıtla bildirilir.**

## Yan Etki Kaydı ve Bağımlılık Listesi

Gövdenin bildirdiği işe **yan etki kaydı (effect)** denir. Kayıt iki parçadan oluşur:
çalışacak işlev ve bir **bağımlılık listesi (dependency list)**. Çalışma zamanı, hesaplanan
farkı belgeye uyguladıktan sonra — bu aşamaya bu kursta **belgeye yazma aşaması (commit)**
denir — kayıtları gözden geçirir ve listesi bir önceki oluşturmadakinden farklı olanları
çalıştırır.

Karşılaştırma öge tek öge kimlik karşılaştırmasıdır; derin bir eşitlik sınaması değildir.
Bunun sonuçları bu dersin sonunda ele alınır.

```js
// yan-etki.mjs — bagimlilik listesi, calisma kosulu ve temizleme sirasi
let etkin = null;
const yaz = (s) => console.log("   " + s);

function yanEtkiKaydi(islev, bagimliliklar) {
  etkin.bekleyen.push({ i: etkin.imlec++, islev, bagimliliklar });
}

// Liste verilmemisse her islemede calisir; verilmisse ogeler tek tek karsilastirilir.
function ayniMi(a, b) {
  if (a === undefined || b === undefined) return false;
  return a.length === b.length && a.every((v, k) => Object.is(v, b[k]));
}

function olustur(o, ozellikler) {
  etkin = o; o.imlec = 0; o.bekleyen = [];
  console.log(`olusturma: istasyon=${ozellikler.istasyon}`);
  o.govde(ozellikler);
  etkin = null;
  for (const kayit of o.bekleyen) {           // islem asamasi: cizimden sonra
    const onceki = o.etkiler[kayit.i];
    if (onceki && ayniMi(onceki.bagimliliklar, kayit.bagimliliklar)) continue;
    if (onceki && onceki.temizle) onceki.temizle();
    kayit.temizle = kayit.islev() || null;
    o.etkiler[kayit.i] = kayit;
  }
}

function sok(o) {
  console.log("agactan cikarma");
  for (const k of o.etkiler) if (k && k.temizle) k.temizle();
  o.etkiler = [];
}

const panel = { etkiler: [], imlec: 0, bekleyen: [] };
panel.govde = ({ istasyon }) => {
  yanEtkiKaydi(() => { yaz("A calisti (liste yok)"); });
  yanEtkiKaydi(() => {
    yaz("B calisti (bos liste)");
    return () => yaz("B temizlendi");
  }, []);
  yanEtkiKaydi(() => {
    yaz(`C calisti: ${istasyon} akisina abone`);
    return () => yaz(`C temizlendi: ${istasyon} aboneligi kesildi`);
  }, [istasyon]);
};

olustur(panel, { istasyon: "KY-01" });
olustur(panel, { istasyon: "KY-01" });
olustur(panel, { istasyon: "KY-02" });
sok(panel);
```

```
olusturma: istasyon=KY-01
   A calisti (liste yok)
   B calisti (bos liste)
   C calisti: KY-01 akisina abone
olusturma: istasyon=KY-01
   A calisti (liste yok)
olusturma: istasyon=KY-02
   A calisti (liste yok)
   C temizlendi: KY-01 aboneligi kesildi
   C calisti: KY-02 akisina abone
agactan cikarma
   B temizlendi
   C temizlendi: KY-02 aboneligi kesildi
```

Listenin üç biçimi çıktıda ayrı ayrı okunur.

**Liste verilmemişse** etki her belgeye yazma aşamasından sonra çalışır. A kaydı dört
oluşturmanın üçünde de çalışmıştır. Bu biçim, eşzamanlanacak değer belirsiz olduğunda
seçilir ve pahalıdır.

**Boş liste** verilmişse etki yalnız ilk oluşturmadan sonra çalışır. B kaydı bir kez
çalışmış ve yalnız ağaçtan çıkarılırken temizlenmiştir. Bileşenin ömrü boyunca bir kez
kurulacak işler — bir gözlemci kurmak, belgeye bir dinleyici bağlamak — bu biçimi kullanır.

**Değer içeren liste** verilmişse karşılaştırma sonucu belirleyicidir. İkinci oluşturmada
istasyon değişmediği için C kaydı hiç çalışmamıştır; üçüncüde değiştiği için çalışmıştır.

## Temizleme

Yan etkinin ikinci yarısı, kurduğu şeyi sökmesidir. Kayıt işlevi bir işlev döndürürse, bu
işlev **temizleme işlevi (cleanup function)** olarak saklanır ve iki anda çağrılır: etki
yeniden çalışmadan hemen önce ve bileşen ağaçtan çıkarılırken.

Üçüncü oluşturmadaki sıra bu yüzden önemlidir. Önce eski abonelik kesilmiş, sonra yenisi
açılmıştır. Ters sıra iki aboneliğin bir an için birlikte var olması demek olurdu; abone
sayısını sayan bir sunucu için bu ölçülebilir bir farktır. Temizlemenin atlanması ise
istasyon her değiştiğinde bir abonelik biriktirir. Bu birikim iki maliyet üretir: kapalı
kalmayan bağlantılar ve — Eşzamansız JavaScript ve Çalışma Zamanı kursunda tanımlanan
sızıntı — artık ağaçta olmayan bir bileşene erişim tutan geri çağırımlar.

Ağaçtan çıkarmada iki temizleme de çalışmıştır. Bu, temizlemenin sözleşmesini tanımlar:
**etkinin kurduğu her şeyin karşılığı temizlemede sökülmelidir.** Dinleyici bağlayan etki
dinleyiciyi kaldırır, zamanlayıcı kuran etki zamanlayıcıyı iptal eder, abone olan etki
aboneliği keser. Temizlemenin kendisi de Kabuk Programlama kursundaki temizlik kancaları
gibi yinelemeye dayanıklı yazılır; zaten kapalı bir bağlantıyı ikinci kez kapatmak hata
üretmemelidir.

## Eşzamansız Etkide Yarış

Temizlemenin en az anlaşılan kullanımı ağ isteklerindedir. Bir istek iptal edilemese bile
sonucunun kullanılması engellenebilir.

```js
// yaris.mjs — eszamansiz yan etkide yanit sirasinin bozulmasi
function kanal() {
  const bekleyen = new Map();
  return {
    getir: (ad) => new Promise((coz) => bekleyen.set(ad, coz)),
    yanitla: (ad) => bekleyen.get(ad)(`${ad} olcumleri`),
  };
}
const bosalt = () => new Promise((coz) => setTimeout(coz, 0));

async function senaryo(koruma) {
  console.log(koruma ? "temizleme var:" : "temizleme yok:");
  const ag = kanal();
  let gorunum = "-";
  let temizle = null;

  // Bagimlilik listesi [istasyon] degistiginde calisan yan etki.
  const etki = (istasyon) => {
    if (temizle) temizle();                 // onceki etkinin temizlenmesi
    let iptal = false;
    ag.getir(istasyon).then((veri) => {
      if (koruma && iptal) { console.log(`  ${veri} geldi, atildi`); return; }
      gorunum = veri;
      console.log(`  gorunum <- ${veri}`);
    });
    temizle = () => { iptal = true; };
  };

  etki("KY-01");              // kullanici once KY-01 seciyor
  etki("KY-02");              // hemen ardindan KY-02 seciyor
  ag.yanitla("KY-02");        // yakin istasyon once yanitladi
  await bosalt();
  ag.yanitla("KY-01");        // uzak istasyon sonra yanitladi
  await bosalt();
  console.log(`  secili istasyon KY-02, ekranda: ${gorunum}`);
}

await senaryo(false);
await senaryo(true);
```

```
temizleme yok:
  gorunum <- KY-02 olcumleri
  gorunum <- KY-01 olcumleri
  secili istasyon KY-02, ekranda: KY-01 olcumleri
temizleme var:
  gorunum <- KY-02 olcumleri
  KY-01 olcumleri geldi, atildi
  secili istasyon KY-02, ekranda: KY-02 olcumleri
```

Kullanıcı iki istasyonu hızlı seçmiş, ikinci istek birinciden önce yanıtlanmıştır. Bu bir
**yarış koşuludur (race condition)**: sonuç, isteklerin gönderilme sırasına değil dönüş
sırasına bağlı kalmıştır. Temizleme olmayan durumda ekranda seçili olmayan istasyonun
ölçümleri durur ve hiçbir hata iletisi yoktur.

Çözüm, her etki çalışmasının kendi geçerlilik bayrağını taşımasıdır. Temizleme bayrağı
düşürür; geç gelen yanıt bayrağı sınayıp kendini atar. Aynı kalıbın taşınabilir biçimi
Eşzamansız JavaScript ve Çalışma Zamanı kursundaki iptal işaretiyle kurulur: temizleme
isteği iptal eder, geç gelen yanıt hiç üretilmez.

## Üç Yaygın Hata

**Eksik bağımlılık.** Listeye yazılmayan bir değer, etkinin ilk çalıştığı oluşturmadaki
kapanışta donar. Etki yeniden çalışmadığı için o değer hiç güncellenmez; bu **eskimiş
kapanıştır (stale closure)**. Kural tektir: etkinin gövdesinde okunan her değişken değer
listeye girer. Listeyi kısaltarak etkinin çalışma sayısını azaltmak, hatayı gizlemekten
başka bir şey yapmaz.

**Her oluşturmada yeniden üretilen bağımlılık.** Karşılaştırma kimlik karşılaştırması
olduğu için, gövde içinde yeniden kurulan bir nesne ya da dizi her oluşturmada farklı
görünür ve etki her seferinde çalışır. Bu, listeyi hiç vermemekle aynı sonuca varır.

**Durumu yan etkiyle türetmek.** Bir değeri başka bir değerden hesaplayıp sonucu duruma
yazan etki, tek bir kullanıcı eyleminden iki oluşturma üretir ve arada tutarsız bir kare
gösterir. Bu hata o kadar yaygındır ki sonraki dersin tamamı buna ayrılmıştır.

## Özet

- Bileşen gövdesi saftır: okur ve hesaplar; dışarıya dokunan iş gövdede yapılmaz, kayıtla
  bildirilir.
- Yan etki kaydı, belgeye yazma aşamasından sonra çalışır; bağımlılık listesi bir önceki
  oluşturmanınkiyle öge tek öge kimlik karşılaştırmasına sokulur.
- Liste verilmemişse etki her yazma aşamasından sonra, boş listeyle yalnız ilk kez,
  değerli listeyle yalnız değerler değiştiğinde çalışır.
- Temizleme işlevi etki yeniden çalışmadan önce ve ağaçtan çıkarmada çağrılır; etkinin
  kurduğu her şeyin karşılığı temizlemede sökülmelidir.
- Eşzamansız etkilerde yanıt sırası istek sırasından farklı olabilir; temizlemenin
  düşürdüğü bir geçerlilik bayrağı geç gelen yanıtı elemenin en küçük yoludur.
- Eksik bağımlılık eskimiş kapanış, her oluşturmada yeniden kurulan nesne ise sürekli
  çalışan etki üretir.

## Sonraki Adım

Yan etki kaydı dış dünyayla eşzamanlama içindir; ne var ki en sık kurulduğu yer dış dünya
değildir. Süzgeç panelinde seçili tür değiştiğinde ölçüm listesini süzen, sonucu bir duruma
yazan ve böylece ikinci bir oluşturma tetikleyen kod yaygın bir kalıptır — ve yanlıştır.
Süzülmüş liste bir durum değil, iki durumdan hesaplanabilen bir sonuçtur; onu ayrı bir
yuvada tutmak ikinci bir doğruluk kaynağı yaratır. Sonraki ders bu ayrımı kurar: hangi
değerler saklanır, hangileri her oluşturmada hesaplanır ve hesap pahalıysa sonucun
saklanmasının ölçülebilir kazancı nedir.
