Ders 09 / 20
Olay Yayıcı
Gözlemci kalıbının yerleşik gerçekleştirimi, yayımın eşzamanlılığı, hata olayının ayrıcalıklı davranışı, dinleyici sınırı uyarısı ve olayların söz biçimiyle beklenmesi.
İçindekiler
Akış dersinde geçen data, end ve drain adları tek bir düzenekten gelir. Aynı
düzenek HTTP sunucusunda, alt süreçlerde ve süreç nesnesinin sinyal bildirimlerinde
de kullanılır: çalışma zamanının eşzamansız arayüzlerinin çoğu bu tek sınıfın
üstüne kurulmuştur.
Bu ders o sınıfı ele alır ve ölçüm toplayıcının veri kaynağını olay tabanlı hâle getirir: kayıt geldiğinde haber veren, eşik aşıldığında uyaran, bozuk satırı bildiren bir kaynak.
Gözlemci Kalıbının Yerleşik Gerçekleştirimi
node:events modülündeki EventEmitter sınıfı, ad başına dinleyici listesi tutar.
on ile listeye eklenir, emit ile liste sırayla çağrılır. Bu, Programlama
Temelleri kursundaki yüksek mertebeden fonksiyon kavramının doğrudan uygulamasıdır:
davranış, bir değer olarak saklanır ve zamanı gelince çağrılır.
Kalıbın kazancı, üretici ile tüketici arasındaki bağı gevşetmesidir. Kaynak, kimin dinlediğini bilmez; dinleyici, kaynağın iç işleyişini bilmez. Aralarındaki tek sözleşme olay adı ve yükün biçimidir.
// yayici.mjs import { EventEmitter } from 'node:events'; class OlcumKaynagi extends EventEmitter { besle(satir) { try { const kayit = JSON.parse(satir); this.emit('olcum', kayit); if (kayit.metrik === 'sicaklik' && kayit.deger > 24) { this.emit('esik-asildi', kayit); } } catch (hata) { this.emit('hata-satiri', { satir, hata }); } } } const kaynak = new OlcumKaynagi(); kaynak.on('olcum', (k) => console.log('olcum :', k.dugum, k.metrik, k.deger)); kaynak.once('esik-asildi', (k) => console.log('esik (bir kez):', k.dugum, k.deger)); kaynak.on('hata-satiri', ({ satir }) => console.log('bozuk satir:', satir)); kaynak.besle('{"dugum":"kenar-01","metrik":"sicaklik","deger":21.4}'); kaynak.besle('{"dugum":"kenar-03","metrik":"sicaklik","deger":24.1}'); kaynak.besle('{"dugum":"kenar-03","metrik":"sicaklik","deger":24.6}'); kaynak.besle('bozuk'); console.log('olcum dinleyici sayisi:', kaynak.listenerCount('olcum')); console.log('esik dinleyici sayisi :', kaynak.listenerCount('esik-asildi'));
node yayici.mjs
olcum : kenar-01 sicaklik 21.4 olcum : kenar-03 sicaklik 24.1 esik (bir kez): kenar-03 24.1 olcum : kenar-03 sicaklik 24.6 bozuk satir: bozuk olcum dinleyici sayisi: 1 esik dinleyici sayisi : 0
once ile eklenen dinleyici ilk yayımdan sonra listeden çıkarılır; çıktının son
satırındaki sıfır bunu doğruluyor. İkinci eşik aşımında uyarı yazılmamış olması da
aynı nedenledir. Kalıcı dinleyici için on, tek seferlik olan için once kullanılır;
elle kaldırmak gerektiğinde off çağrısına dinleyicinin aynı referansı verilmelidir
— adsız bir fonksiyon ifadesiyle eklenen dinleyici bir daha kaldırılamaz.
Yayım Eşzamanlıdır
Ad “olay” olduğu için bir kuyruğa girdiği sanılabilir. Öyle değildir: emit,
dinleyicileri eklenme sırasına göre o anda çağırır ve hepsi bitince döner.
// yayici-senkron.mjs import { EventEmitter } from 'node:events'; const y = new EventEmitter(); y.on('olay', () => console.log('2 dinleyici')); console.log('1 emit oncesi'); y.emit('olay'); console.log('3 emit sonrasi');
node yayici-senkron.mjs
1 emit oncesi 2 dinleyici 3 emit sonrasi
Bunun iki sonucu vardır. Birincisi, dinleyici içinde yapılan uzun senkron iş, olay
döngüsünü diğer her şey gibi durdurur; olay yaymak işi ertelemez. İkincisi, dinleyici
içinde fırlatılan bir hata emit çağrısının yapıldığı yere doğru yayılır — kaynak
kodunun ortasına, hiç beklemediği bir yere.
Bir dinleyicinin işini erteleyerek çağıranı serbest bırakması gerekiyorsa erteleme açıkça yazılır: iş bir zamanlayıcıya veya mikro göreve bırakılır. Kaynağın kendisi bu kararı veremez.
Hata Olayının Ayrıcalığı
error adı, sınıf içinde özel olarak ele alınır. Bu ada dinleyici yokken yayım
yapılırsa, yük fırlatılır ve yakalanmazsa süreç sonlanır.
// yayici-hata.mjs import { EventEmitter } from 'node:events'; const dinleyicili = new EventEmitter(); dinleyicili.on('error', (h) => console.log('yakalandi:', h.message)); dinleyicili.emit('error', new Error('kaynak kapandi')); const dinleyicisiz = new EventEmitter(); dinleyicisiz.emit('error', new Error('bu firlatilacak')); console.log('bu satira ulasilmaz');
Standart çıktıya yalnızca tek bir satır düşer:
node yayici-hata.mjs 2>/dev/null
yakalandi: kaynak kapandi
Süreç ikinci yayımda sonlanır; bu satira ulasilmaz satırı yazılmaz ve standart
hataya bir yığıt izi düşer. İzin içeriği dosya yollarını taşıdığı için makineye göre
değişir.
Bu davranış bilinçli bir tasarımdır. Eşzamansız bir kaynağın hatası sessizce
yutulursa, program yanlış veriyle çalışmaya devam eder ve arıza çok sonra, ilgisiz
bir yerde görünür. Kural şudur: hata yayabilen her nesneye bir error dinleyicisi
takılır. Akış nesneleri de birer olay yayıcı olduğundan bu kural onlar için de
geçerlidir; önceki derste pipeline kullanmanın gerekçelerinden biri, bu dinleyiciyi
zincirdeki her akış için kendiliğinden kurmasıdır.
Dinleyici Sınırı
Bir ada eklenen dinleyici sayısı varsayılan sınırı aştığında çalışma zamanı bir uyarı yazar:
// yayici-sinir.mjs import { EventEmitter } from 'node:events'; const y = new EventEmitter(); for (let i = 0; i < 11; i += 1) y.on('olcum', () => {}); console.log('dinleyici sayisi:', y.listenerCount('olcum'));
node yayici-sinir.mjs
dinleyici sayisi: 11 (node:59045) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 olcum listeners added to [EventEmitter]. MaxListeners is 10. Use emitter.setMaxListeners() to increase limit
Uyarı satırının başındaki sayı süreç kimliğidir ve her çalıştırmada değişir. Uyarı bir hata değildir; program çalışmaya devam eder.
Uyarının gerekçesi şudur: dinleyici listesi büyümeye devam ediyorsa, bu genellikle her istekte yeni dinleyici eklendiği ve hiç kaldırılmadığı anlamına gelir. Liste büyüdükçe kapatılan fonksiyonların tuttuğu değerler de serbest bırakılamaz ve bellek sızıntısı oluşur — Eşzamansız JavaScript ve Çalışma Zamanı kursunda erişilebilirlik temelli çöp toplama anlatılırken kurulan durum tam olarak budur.
Gerçekten çok dinleyici gerekiyorsa sınır setMaxListeners ile yükseltilir. Sınırı
yükseltmeden önce, listenin neden büyüdüğü açıklanmalıdır.
Olayları Söz Olarak Beklemek
Olay tabanlı arayüzü async/await ile birleştirmek için modül iki yardımcı sunar.
once fonksiyonu tek bir olayı bekleyen söz döndürür; on fonksiyonu ise olayları
eşzamansız yinelenebilir hâle getirir.
// yayici-soz.mjs import { EventEmitter, once, on } from 'node:events'; const kaynak = new EventEmitter(); // Tek bir olayi beklemek: soz olarak setTimeout(() => kaynak.emit('hazir', { dugum: 'kenar-01' }), 20); const [yuk] = await once(kaynak, 'hazir'); console.log('once ile beklendi:', yuk); // Surekli akan olaylari yinelemek setTimeout(() => { kaynak.emit('olcum', 21.4); kaynak.emit('olcum', 21.9); kaynak.emit('bitti'); }, 20); const durdurucu = new AbortController(); kaynak.once('bitti', () => durdurucu.abort()); try { for await (const [deger] of on(kaynak, 'olcum', { signal: durdurucu.signal })) { console.log('akan olay :', deger); } } catch (hata) { if (hata.name !== 'AbortError') throw hata; console.log('yineleme sonlandi:', hata.name); }
node yayici-soz.mjs
once ile beklendi: { dugum: 'kenar-01' }
akan olay : 21.4
akan olay : 21.9
yineleme sonlandi: AbortError
Her iki yardımcı da dinleyici argümanlarını dizi olarak verir; tek argümanlı olaylarda çözümleme ile ilk öğe alınır.
İkinci bölümdeki durdurucu, sonsuz yinelemeyi bitirmenin yoludur. on ile kurulan
döngü kendiliğinden sonlanmaz — kaynak olay yaymayı bıraksa bile döngü beklemeye
devam eder. Sonlandırma bir iptal işaretiyle yapılır ve iptal, yineleyiciden bir
AbortError olarak çıkar. Bu, Eşzamansız JavaScript ve Çalışma Zamanı kursunda
istek iptali için tanıtılan aynı düzenektir.
Bir uyarı: on ile kurulan yineleme, döngü gövdesi çalışırken gelen olayları
biriktirir. Gövde yavaşsa bu birikim sınırsızdır; olay yayıcı, akışların aksine geri
basınç taşımaz. Yüksek hacimli kaynaklarda olay yayıcı yerine akış kullanılmasının
nedeni budur.
Özet
- Olay yayıcı, ad başına dinleyici listesi tutan gözlemci kalıbı gerçekleştirimidir; çalışma zamanının eşzamansız arayüzlerinin çoğu bu sınıfın üstüne kuruludur.
emiteşzamanlıdır: dinleyicileri eklenme sırasına göre o anda çağırır ve hepsi bitince döner; yayım işi ertelemez.erroradı ayrıcalıklıdır; dinleyicisiz yayım yükü fırlatır ve süreci sonlandırır. Hata yayabilen her nesneye dinleyici takılır.- Dinleyici sayısı sınırı aştığında yazılan uyarı, çoğunlukla kaldırılmayan dinleyici birikimini ve buna bağlı bellek sızıntısını haber verir.
onceveonyardımcıları olayları söz ve eşzamansız yineleme biçimine çevirir; yineleme bir iptal işaretiyle sonlandırılır ve geri basınç taşımaz.
Sonraki Adım
Ölçüm toplayıcının bütün parçaları hazır: dosyadan akışla okuma, kayıt kurma, özetleme ve olay tabanlı bildirim. Eksik olan tek şey, özetin dışarıya sunulmasıdır. Sonraki ders HTTP sunucusunu kurar: isteğin okunabilir, yanıtın yazılabilir bir akış olduğu; İnternet Nasıl Çalışır kursunda satır satır incelenen istek ve yanıt yapısının kodda nasıl karşılandığı ele alınacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.