EventEmitter, Node'un events modülünde bulunan ve bir nesnenin isimli olaylar duyurmasını sağlayan sınıftır. emitter.on('name', fn) ile bir listener kaydedersin ve emitter.emit('name', ...args) ile onu tetiklersin; o isimdeki her listener, eklendiği sırayla ve verdiğin argümanlarla çalışır. HTTP sunucuları, stream'ler ve process birer EventEmitter'dır, bu yüzden aynı birkaç metot Node'un her yerinde çalışır.
İki listener da before emit ile after emit arasında çalışır: emit onları senkron çağırır ve ancak bittiklerinde döner. İki shop.on çağrısının yerini değiştirirsen ortadaki iki satırın da yeri değişir.
on, once ve off
on bir listener'ı sen silene kadar tutar, once onu ilk çağrıdan sonra siler, off (removeListener ile aynı) ise birini siler. Bir listener'ı silmek için eklediğin fonksiyonun aynısına ihtiyacın var, bu yüzden arrow function'ı satır içinde vermek yerine fonksiyona bir isim ver.
first open ever bir kez, Ada'dan sonra yazdırılır. logOpen silindikten sonra dinleyen kimse kalmaz, bu yüzden son emit false döndürür; door.removeAllListeners('open') iki listener'ı tek çağrıda temizlerdi.
| Metot | Ne yapar |
|---|---|
on(name, fn), addListener | Her emit'te fn'i çağırır |
once(name, fn) | fn'i yalnızca bir sonraki emit'te çağırır |
prependListener(name, fn) | on gibi, ama mevcut listener'lardan önce çalışır |
off(name, fn), removeListener | O fonksiyonu siler |
emit(name, ...args) | Listener'ları çağırır, en az biri varsa true döndürür |
listenerCount(name) | Olayın kaç listener'ı olduğu |
error olayı
'error' özeldir. Onu emit edersen ve kimse dinlemiyorsa emit hatayı fırlatır ve gerçek bir programda yakalanmamış bir throw süreci çökertir. Stream'ler ve sunucular gibi hata verebilecek emitter'lara her zaman bir 'error' listener'ı ekle.
Listener yokken emit hata fırlatır ve onu catch yakalar; listener eklendikten sonra aynı emit sadece onu çağırır ve program devam eder. Listener'ı olmayan diğer olay isimleri sessizce yok sayılır.
Kendi sınıfında EventEmitter'ı extend et
Olağan kullanım şekli, sınıfının EventEmitter'ı extend etmesi, constructor'da super() çağırması ve bir şey olduğunda this.emit kullanmasıdır. Sonra çağıranlar nesnene herhangi bir Node nesnesine abone olur gibi abone olur.
Önce 25%, 50%, 75%, 100%, ardından photo.png uploaded yazdırılır. up.start() satırını iki up.on satırının üstüne taşırsan hiçbir şey yazdırılmaz: olaylar kimse dinlemeden tetiklenir.
Aynı tuzak constructor'dan emit ederken de geçerlidir. Hemen emit etmesi gereken kütüphaneler çağrıyı process.nextTick ile sarar; bu, çağıranın on satırlarından sonra çalışır (bkz. event loop sayfası).
events.once ile bir olayı bekle
events.once(emitter, name), olay bir sonraki sefer emit edildiğinde olayın argümanlarıyla, bir dizi olarak, resolve olan bir promise döndürür. Tek seferlik bir olayı await edebileceğin bir şeye çevirir ve emitter önce 'error' emit ederse reject olur.
await, timer ready olayını emit edene kadar bekler, sonra dizi iki argümana ayrıştırılır. Birçok kez tetiklenen bir olay için events.on(emitter, name), for await ile üzerinde döngü kurabileceğin bir async iterator verir.
Sık yapılan hatalar
Sık çalışan bir fonksiyonun içinde listener eklemek. Her request handler'da on çağırmak listener'ları ve belleği üst üste yığar. Bir kez ekle ya da once kullan.
Satır içi bir fonksiyonu silmeye çalışmak. off('data', () => ...) hiçbir şey silmez, çünkü o arrow function yepyeni bir fonksiyondur. Eklediğin fonksiyona bir referans tut.
Listener'ların daha sonra çalışmasını beklemek. emit senkrondur, yani yavaş bir listener emit eden kodu bekletir. Listener'ı async yapmak işe yaramaz, çünkü kodu ilk await satırına kadar yine aynı thread'de çalışır. Ağır işi aralarına setImmediate koyarak parçalara böl ya da bir worker thread'e taşı.
Sıkça Sorulan Sorular
EventEmitter asenkron mu?
Hayır. emit her listener'ı hemen, birbiri ardına çağırır ve sonuncusu bitince döner. Bir listener'ın içindeki kod async bir iş başlatabilir, ama listener'ın kendisi senkron çağrılır.
MaxListenersExceededWarning ne anlama geliyor?
Node, bir olay için 10'dan fazla listener eklendiğinde uyarır, çünkü bu genelde her istekte bir listener eklenip hiç silinmediği anlamına gelir. Fazla listener'ları sil ya da gerçekten daha fazlasına ihtiyacın varsa emitter.setMaxListeners(n) çağır.
emit ne döndürür?
Olayın en az bir listener'ı varsa true, kimse dinlemiyorsa false. Listener'ların döndürdüğü değeri döndürmez.
Hangi Node.js nesneleri EventEmitter'dır?
Node'un çekirdek nesnelerinin çoğu: HTTP sunucuları, request ve response'lar, stream'ler, soketler, process ve readline arayüzleri. Hepsinin on, once ve off metotlarını paylaşmasının nedeni bu.