EventEmitter adalah class di module events milik Node yang memungkinkan sebuah object mengumumkan event bernama. Kamu mendaftarkan listener dengan emitter.on('name', fn) dan memicunya dengan emitter.emit('name', ...args); setiap listener untuk nama itu berjalan, sesuai urutan pemasangannya, dengan argumen yang kamu berikan. HTTP server, stream, dan process semuanya adalah EventEmitter, jadi beberapa method yang sama ini bekerja di mana saja di Node.
Kedua listener berjalan di antara before emit dan after emit: emit memanggilnya secara synchronous dan baru kembali setelah keduanya selesai. Tukar posisi dua panggilan shop.on dan dua baris di tengah ikut tertukar.
on, once dan off
on menyimpan listener sampai kamu melepasnya, once melepasnya setelah panggilan pertama, dan off (sama dengan removeListener) melepas satu listener. Untuk melepas listener kamu butuh fungsi yang sama dengan yang kamu pasang, jadi beri nama fungsinya alih-alih menulis arrow function langsung di tempat.
first open ever tercetak sekali, setelah Ada. Begitu logOpen dilepas, tidak ada yang mendengarkan lagi, jadi emit terakhir mengembalikan false; door.removeAllListeners('open') akan menghapus kedua listener dalam satu panggilan.
| Method | Fungsinya |
|---|---|
on(name, fn), addListener | Memanggil fn di setiap emit |
once(name, fn) | Memanggil fn hanya di emit berikutnya |
prependListener(name, fn) | Seperti on, tetapi berjalan sebelum listener yang sudah ada |
off(name, fn), removeListener | Melepas fungsi itu |
emit(name, ...args) | Memanggil listener, mengembalikan true kalau ada |
listenerCount(name) | Jumlah listener yang dimiliki event itu |
Event error
'error' itu istimewa. Kalau kamu memancarkannya dan tidak ada yang mendengarkan, emit melempar error-nya, dan di program sungguhan, throw yang tidak ditangkap membuat proses crash. Selalu pasang listener 'error' di emitter yang bisa gagal, seperti stream dan server.
Tanpa listener, emit melempar error dan catch menangkapnya; setelah listener dipasang, emit yang sama hanya memanggilnya dan program terus berjalan. Nama event lain yang tidak punya listener diabaikan begitu saja.
Extend EventEmitter di class milikmu
Cara pakai yang umum adalah membuat class-mu extends EventEmitter, memanggil super() di constructor, dan this.emit saat sesuatu terjadi. Pemanggil lalu bisa subscribe ke object-mu seperti ke object Node mana pun.
Hasilnya 25%, 50%, 75%, 100%, lalu photo.png uploaded. Pindahkan up.start() ke atas dua baris up.on dan tidak ada yang tercetak: event-nya terpancar sebelum ada yang mendengarkan.
Jebakan yang sama berlaku saat memancarkan event dari constructor. Library yang harus langsung memancarkan event membungkus panggilannya dengan process.nextTick, yang berjalan setelah baris on milik pemanggil (lihat halaman event loop).
Menunggu event dengan events.once
events.once(emitter, name) mengembalikan promise yang resolve dengan argumen event itu, dalam bentuk array, saat event itu dipancarkan berikutnya. Fungsi ini mengubah event sekali-jalan menjadi sesuatu yang bisa kamu await, dan promise-nya reject kalau emitter memancarkan 'error' lebih dulu.
await menjeda sampai timer memancarkan ready, lalu array-nya di-destructure menjadi dua argumen. Untuk event yang terpancar berkali-kali, events.on(emitter, name) memberimu async iterator yang bisa kamu ulangi dengan for await.
Kesalahan umum
Memasang listener di dalam fungsi yang sering berjalan. Memanggil on di setiap request handler menumpuk listener dan memakan memori. Pasang sekali saja, atau pakai once.
Melepas fungsi yang ditulis langsung di tempat. off('data', () => ...) tidak melepas apa pun, karena arrow function itu adalah fungsi baru. Simpan referensi ke fungsi yang kamu pasang.
Mengira listener akan berjalan belakangan. emit itu synchronous, jadi listener yang lambat menahan kode yang memancarkannya. Menandai listener sebagai async tidak membantu, karena kodenya tetap berjalan di thread yang sama sampai await pertama. Pecah pekerjaan berat menjadi beberapa bagian dengan setImmediate di antaranya, atau pindahkan ke worker thread.
Pertanyaan yang sering diajukan
Apakah EventEmitter asynchronous?
Tidak. emit langsung memanggil setiap listener, satu per satu, dan baru kembali saat listener terakhir selesai. Kode di dalam listener bisa memulai pekerjaan async, tetapi listener itu sendiri dipanggil secara synchronous.
Apa arti MaxListenersExceededWarning?
Node memberi peringatan saat lebih dari 10 listener dipasang untuk satu event, karena itu sering berarti sebuah listener dipasang di setiap request dan tidak pernah dilepas. Lepaskan listener yang berlebih, atau panggil emitter.setMaxListeners(n) kalau kamu memang butuh lebih banyak.
Apa yang dikembalikan emit?
true kalau event itu punya paling sedikit satu listener, false kalau tidak ada yang mendengarkan. emit tidak mengembalikan nilai yang dikembalikan listener.
Object Node.js mana saja yang merupakan EventEmitter?
Sebagian besar object inti Node: HTTP server, request dan response, stream, socket, process, dan interface readline. Itulah sebabnya semuanya sama-sama punya on, once, dan off.