---
title: 'Olay Modeli'
source: 'https://academia.sh/tr/kurslar/tarayici-platformu/olay-modeli'
course: 'Tarayıcı ve Web Platformu'
language: tr
updated: '2026-08-17T18:09:12+00:00'
license: 'CC BY-SA 4.0'
---

# Olay Modeli

Bir olayın kökten hedefe ve hedeften köke izlediği yol; yakalama, hedef ve kabarcık evreleri, dinleyici sırası, yayılımı durdurmanın iki biçimi ve dinleyici kimliği.

Önceki ders belgeyi okumayı ve değiştirmeyi kurdu. Değişikliği neyin tetikleyeceği açık
kalmıştı: bir sayfa kendiliğinden değişmez, kullanıcının ya da tarayıcının ürettiği bir
bildirime yanıt olarak değişir. Bu bildirime **olay (event)** denir.

Olayın hangi düğüme ait olduğu ilk bakışta bellidir — tıklanan düğme, yazılan alan. Asıl
soru şudur: olay yalnızca o düğüme mi bildirilir? Yanıt hayırdır ve bu dersin konusu,
olayın ağaç üzerinde izlediği tanımlı yoldur.

## Olay Bir Nesnedir

Bir olay, tarayıcının ürettiği ve dinleyiciye argüman olarak verdiği bir nesnedir. Üç
alanı her olayda bulunur.

**Tür (type)** olayın adıdır: `click`, `input`, `submit`, `keydown`. Dinleyici bir türe
kaydolur; başka türdeki olaylar onu çağırmaz.

**Hedef (target)** olayın kaynaklandığı düğümdür. Tıklama olayında bu, imlecin altında
kalan en derin ögedir — satırın kendisine tıklanmış gibi görünse bile, hedef o satırdaki
düğmedir.

**Geçerli hedef (currentTarget)** dinleyicinin bağlı olduğu düğümdür. Bu ikisi yalnızca
dinleyici hedefin kendisine bağlandığında aynıdır; başka her durumda ayrışırlar ve bu
ayrım sonraki dersin tamamının dayanağıdır.

Dinleyicinin ne zaman çalıştığı, Eşzamansız JavaScript ve Çalışma Zamanı kursundaki Olay
Döngüsü dersinde tanımlanan modele bağlıdır: olay üretildiğinde dinleyici hemen çağrılmaz,
bir görev olarak kuyruğa alınır ve çağrı yığıtı boşaldığında çalıştırılır. Uzun süren bir
dinleyici bu yüzden yalnızca kendini geciktirmez, kuyruktaki bütün olayları geciktirir.

## Yayılım Yolu

Bir olay üretildiğinde tarayıcı önce **yayılım yolunu (propagation path)** hesaplar: kök
düğümden hedefe kadar uzanan ata zinciri. Bu yol olay yayılmaya başlamadan önce belirlenir
ve yayılım sırasında ağaç değişse bile değişmez.

Yol boyunca her düğüm iki kez ziyaret edilir: bir kez kökten hedefe inerken, bir kez
hedeften köke çıkarken. Bu iki geçiş üç evre üretir.

**Yakalama evresi (capture phase)** kökten hedefin ebeveynine kadar iner. Atalara bağlı
ve yakalama kipinde kaydedilmiş dinleyiciler burada çağrılır.

**Hedef evresi (target phase)** hedefin kendisidir.

**Kabarcık evresi (bubble phase)** hedefin ebeveyninden köke çıkar. Atalara bağlı ve
kabarcık kipinde kaydedilmiş dinleyiciler burada çağrılır.

```js
// yayilim.mjs — uc evreli olay yayiliminin kucuk bir modeli
const oge = (ad, ...cocuklar) => {
  const d = { ad, cocuklar, ebeveyn: null, dinleyiciler: [] };
  for (const c of cocuklar) c.ebeveyn = d;
  return d;
};

const dinle = (dugum, tur, etiket, yakalamada = false) =>
  dugum.dinleyiciler.push({ tur, etiket, yakalamada });

// Hedeften koke yurunur, ters cevrilir: yol her zaman kokten hedefe dogrudur.
function yol(hedef) {
  const zincir = [];
  for (let d = hedef; d; d = d.ebeveyn) zincir.push(d);
  return zincir.reverse();
}

const EVRE_ADI = { 1: "yakalama", 2: "hedef", 3: "kabarcık" };

function yay(hedef, tur) {
  const zincir = yol(hedef);
  const cagrilar = [];

  const calistir = (dugum, evre, yakalamada) => {
    for (const d of dugum.dinleyiciler) {
      if (d.tur !== tur || d.yakalamada !== yakalamada) continue;
      cagrilar.push({ evre, dugum: dugum.ad, dinleyici: d.etiket });
    }
  };

  for (const dugum of zincir.slice(0, -1)) calistir(dugum, 1, true);   // yakalama
  calistir(hedef, 2, true);                                            // hedef
  calistir(hedef, 2, false);                                           // hedef
  for (const dugum of zincir.slice(0, -1).reverse()) calistir(dugum, 3, false); // kabarcık

  return cagrilar;
}

const dugme = oge("button.kaydet");
const satir = oge("tr.olcum", dugme);
const tablo = oge("table#gunluk", satir);
const ana = oge("main", tablo);
const govde = oge("body", ana);

dinle(govde, "click", "govde-yakalama", true);
dinle(ana, "click", "ana-yakalama", true);
dinle(tablo, "click", "tablo-kabarcik");
dinle(satir, "click", "satir-yakalama", true);
dinle(satir, "click", "satir-kabarcik");
dinle(dugme, "click", "dugme-1");
dinle(dugme, "click", "dugme-2", true);

console.log("yol:", yol(dugme).map((d) => d.ad).join(" > "));
console.log();
for (const c of yay(dugme, "click")) {
  console.log(String(c.evre).padEnd(2), EVRE_ADI[c.evre].padEnd(9), c.dugum.padEnd(14), c.dinleyici);
}
```

```
yol: body > main > table#gunluk > tr.olcum > button.kaydet

1  yakalama  body           govde-yakalama
1  yakalama  main           ana-yakalama
1  yakalama  tr.olcum       satir-yakalama
2  hedef     button.kaydet  dugme-2
2  hedef     button.kaydet  dugme-1
3  kabarcık  tr.olcum       satir-kabarcik
3  kabarcık  table#gunluk   tablo-kabarcik
```

Çıktı, istasyon sayfasındaki ölçüm tablosunda bir satırın kaydet düğmesine tıklandığında
ne olduğunu gösterir. Yedi dinleyici kayıtlıdır ve yedisi de çağrılır; çağrılma sırası
kayıt sırasına değil, düğümün yoldaki konumuna ve dinleyicinin evresine bağlıdır.

`table#gunluk` düğümüne bağlı `tablo-kabarcik` dinleyicisi kayıt sırasında üçüncüdür ama
çağrı sırasında sonuncudur. Bunun nedeni, kabarcık evresinin yolu ters yönde
dolaşmasıdır: hedefe en yakın ata önce, en uzak ata en sonra çağrılır.

## Hedefteki Sıra

Çıktının dördüncü ve beşinci satırı bir ayrıntı taşır: `dugme-2` kayıtta sonuncu olmasına
karşın `dugme-1` den önce çağrılmıştır. Aradaki tek fark, `dugme-2` nin yakalama kipinde
kaydedilmiş olmasıdır.

Nedeni yolun iki kez dolaşılmasıdır. Hedef düğüm her iki geçişte de ziyaret edilir: inen
geçişte yakalama kipindeki dinleyicileri, çıkan geçişte kabarcık kipindekiler çağrılır.
Evre adı ikisinde de "hedef" olarak bildirilir; sıra ise geçişten gelir.

Bu davranış, aynı düğüme hem yakalama hem kabarcık kipinde dinleyici bağlanan durumlarda
şaşırtıcı olabilir. Kural sadedir: **aynı düğümde yakalama kipindeki dinleyiciler her
zaman önce çalışır**, kayıt sırasından bağımsız olarak. Aynı kipteki dinleyiciler ise
kendi aralarında kayıt sırasını korur.

## Yayılımı Durdurmak

Bir dinleyici, olayın yoldaki yolculuğunu kesebilir. İki ayrı işlem vardır ve etkileri
farklıdır.

```js
// durdurma.mjs — yayilimi durdurmanin iki bicimi ve kabarmayan olay
const oge = (ad, ...cocuklar) => {
  const d = { ad, cocuklar, ebeveyn: null, dinleyiciler: [] };
  for (const c of cocuklar) c.ebeveyn = d;
  return d;
};
const dinle = (dugum, etiket, secenek = {}) =>
  dugum.dinleyiciler.push({ etiket, yakalamada: secenek.yakalamada ?? false, eylem: secenek.eylem });

function yol(hedef) {
  const zincir = [];
  for (let d = hedef; d; d = d.ebeveyn) zincir.push(d);
  return zincir.reverse();
}

function yay(hedef, { kabarir = true } = {}) {
  const zincir = yol(hedef);
  const olay = { durduruldu: false, hemenDurduruldu: false, cagrilanlar: [] };

  const calistir = (dugum, yakalamada) => {
    for (const d of dugum.dinleyiciler) {
      if (d.yakalamada !== yakalamada) continue;
      if (olay.hemenDurduruldu) return;      // ayni dugumdeki kalanlari da atlar
      olay.cagrilanlar.push(dugum.ad + "/" + d.etiket);
      d.eylem?.(olay);
    }
  };

  for (const d of zincir.slice(0, -1)) {
    if (olay.durduruldu) break;              // sonraki dugume gecilmez
    calistir(d, true);
  }
  if (!olay.durduruldu) calistir(hedef, true);
  if (!olay.durduruldu) calistir(hedef, false);
  if (kabarir) {
    for (const d of zincir.slice(0, -1).reverse()) {
      if (olay.durduruldu) break;
      calistir(d, false);
    }
  }
  return olay.cagrilanlar;
}

function agacKur(satirEylem) {
  const dugme = oge("button");
  const satir = oge("tr", dugme);
  const tablo = oge("table", satir);
  const govde = oge("body", tablo);
  dinle(govde, "govde-yakalama", { yakalamada: true });
  dinle(satir, "satir-yakalama", { yakalamada: true, eylem: satirEylem });
  dinle(dugme, "dugme-1");
  dinle(dugme, "dugme-2");
  dinle(satir, "satir-kabarcik");
  dinle(tablo, "tablo-kabarcik");
  return dugme;
}

console.log("engelsiz          :", yay(agacKur(undefined)).join(" → "));
console.log("stopPropagation   :", yay(agacKur((o) => { o.durduruldu = true; })).join(" → "));
console.log("kabarmayan olay   :", yay(agacKur(undefined), { kabarir: false }).join(" → "));

// stopImmediatePropagation ayni dugumdeki sonraki dinleyiciyi de engeller.
const dugme = oge("button");
const govde2 = oge("body", dugme);
dinle(govde2, "govde-kabarcik");
dinle(dugme, "dugme-1", { eylem: (o) => { o.hemenDurduruldu = true; o.durduruldu = true; } });
dinle(dugme, "dugme-2");
console.log("stopImmediate...  :", yay(dugme).join(" → "));
```

```
engelsiz          : body/govde-yakalama → tr/satir-yakalama → button/dugme-1 → button/dugme-2 → tr/satir-kabarcik → table/tablo-kabarcik
stopPropagation   : body/govde-yakalama → tr/satir-yakalama
kabarmayan olay   : body/govde-yakalama → tr/satir-yakalama → button/dugme-1 → button/dugme-2
stopImmediate...  : button/dugme-1
```

`stopPropagation`, olayın **sonraki düğüme** geçmesini engeller. Aynı düğüme bağlı diğer
dinleyiciler yine de çağrılır. İkinci satırda yakalama evresinde satırda durdurulan olay
hedefe hiç ulaşmamıştır — düğmenin kendi dinleyicileri çalışmamıştır.

`stopImmediatePropagation` buna ek olarak **aynı düğümdeki kalan dinleyicileri** de atlar.
Son satırda `dugme-2` çağrılmamıştır.

İkisi arasındaki seçim bir tasarım kararıdır. `stopPropagation` çağıran kod, ağacın
yukarısında ne olduğunu bilmeden onu iptal eder. Sayfanın başka bir yerinde belgenin
tamamına bağlanmış bir dinleyici — açık bir menüyü kapatan ya da bir ölçümü kaydeden —
sessizce devre dışı kalır. Bu nedenle yayılımı durdurmak, iki kod parçasının birbirini
bilmeden etkilediği bir bağımlılık üretir ve son çare olarak kullanılır.

## Kabaran ve Kabarmayan Olaylar

Her olay kabarmaz. Çıktının üçüncü satırı bunu gösterir: kabarmayan bir olayda yakalama
ve hedef evreleri olduğu gibi çalışır, yalnızca kabarcık evresi atlanır.

Bu ayrım sık yanlış anlaşılır. Kabarmayan bir olay "yalnızca hedefe ulaşır" değildir;
atalarına yakalama kipinde bağlanmış dinleyiciler onu görür. Yalnızca kabarcık kipindeki
ata dinleyicileri görmez.

Kabarmayan olayların örnekleri belirli bir mantığa uyar: bir ögeye özgü olan ve ata
düğümler için anlamı olmayan bildirimler kabarmaz. Odak alma ve odak kaybetme olayları
kabarmaz; aynı bilgiyi kabaran bir çiftle veren ayrı olay türleri tanımlıdır. Bir görselin
yüklenmesi kabarmaz. Kullanıcı girdisinden doğan olaylar — tıklama, tuş basımı, girdi,
gönderim — kabarır.

Bir olayın kabarıp kabarmadığı olay nesnesinin `bubbles` alanından okunabilir; bu, belgeye
bakarak tahmin etmekten güvenilir bir yoldur.

## Dinleyici Kimliği

Bir dinleyicinin kaydı üç bilgiyle tanımlanır: olay türü, işlev başvurusu ve yakalama
kipi. Aynı üçlüyle ikinci kez kayıt yapmak yeni bir dinleyici eklemez, yok sayılır. Buna
karşılık aynı işlev farklı kiple kaydedilirse iki ayrı dinleyici olur.

Kaldırma da aynı üçlüyle yapılır. Buradan yaygın bir hata çıkar: kayıt sırasında yerinde
tanımlanmış bir işlev, kaldırma sırasında tekrar yazıldığında **başka bir işlevdir** ve
eşleşme kurulamaz. Kaldırılabilir olması gereken dinleyicinin işlevi bir ada bağlanmalıdır.

Kaydın seçenekleri arasında iki tanesi bu sorunu kaynağında çözer. `once` seçeneği,
dinleyiciyi ilk çağrıdan sonra kendiliğinden kaldırır. `signal` seçeneği, Eşzamansız
JavaScript ve Çalışma Zamanı kursundaki İptal ve Zaman Aşımı dersinde tanımlanan iptal
işaretini kabul eder; işaret iptal edildiğinde o işarete bağlı bütün dinleyiciler tek
hamlede kaldırılır. Çok sayıda dinleyici kaydeden bir bileşenin temizliği bu yolla tek
satıra iner.

## Özet

- Olay üretildiğinde önce yayılım yolu hesaplanır: kökten hedefe uzanan ata zinciri. Yol
  yayılım başlamadan sabitlenir.
- Yol iki kez dolaşılır ve üç evre üretir: yakalama (kökten hedefe), hedef, kabarcık
  (hedeften köke).
- Aynı düğümde yakalama kipindeki dinleyiciler kabarcık kipindekilerden önce çalışır; aynı
  kip içinde kayıt sırası korunur.
- `stopPropagation` olayın sonraki düğüme geçmesini, `stopImmediatePropagation` buna ek
  olarak aynı düğümdeki kalan dinleyicileri de engeller.
- Kabarmayan olaylarda yalnızca kabarcık evresi atlanır; yakalama ve hedef evreleri
  değişmez.
- Dinleyici kimliği tür, işlev başvurusu ve yakalama kipi üçlüsüdür; kaldırma aynı üçlüyü
  gerektirir, `once` ve `signal` seçenekleri bu gereği ortadan kaldırır.

## Sonraki Adım

Bu ders olayın hedefe ulaşmadan ve ulaştıktan sonra atalarından geçtiğini gösterdi. Bu
yolculuk bir yük değil, bir olanaktır: hedefin atasına bağlanmış tek bir dinleyici, o
atanın altındaki bütün ögelerin olaylarını görebilir. Ölçüm tablosunun her satırına ayrı
dinleyici bağlamak yerine tabloya tek dinleyici bağlamak, hem kayıt sayısını hem de
sonradan eklenen satırların dinleyicisiz kalması sorununu ortadan kaldırır. Sonraki ders
bu tekniği, hedefi ata düğümden ayırt etme kuralıyla birlikte kurar.
