Ce face EventEmitter (node:events)
Un EventEmitter ține o listă de funcții (ascultători) pentru fiecare nume de eveniment. on(nume, fn) adaugă un ascultător, once unul care rulează o singură dată, off (sau removeListener) îl scoate, iar emit(nume, ...argumente) le apelează pe toate, sincron, în ordinea înregistrării. Stream-urile, serverul HTTP și procesele copil sunt toate EventEmitter.
Evenimentul "error" este special: dacă îl emiți și nu are niciun ascultător, eroarea este aruncată și oprește procesul. De aceea orice obiect care poate emite erori trebuie să aibă .on("error", ...).
Funcțiile events.once(emitter, nume) și events.on(emitter, nume) leagă evenimentele de async/await: prima întoarce o promisiune pentru următorul eveniment, a doua un iterator asincron pentru toate evenimentele. Peste 10 ascultători pe același eveniment, Node.js afișează un avertisment (posibilă scurgere de memorie).
Parametri
| Parametru | Descriere |
|---|---|
on(nume, fn) / addListener |
Adaugă un ascultător. |
once(nume, fn) |
Ascultător care se scoate singur după primul apel. |
emit(nume, ...arg) |
Apelează ascultătorii; întoarce true dacă a existat cel puțin unul. |
off(nume, fn) / removeListener |
Scoate un ascultător (aceeași funcție dată la on). |
listenerCount(nume) |
Numărul de ascultători. |
Ce returnează
on, once, off întorc emițătorul (se pot înlănțui); emit întoarce true sau false.
Exemple
Exemplul 1: O clasă care emite evenimente
import { EventEmitter } from "node:events";
class Magazin extends EventEmitter {
#stoc = new Map([["mere", 2]]);
vinde(produs) {
const ramas = (this.#stoc.get(produs) ?? 0) - 1;
if (ramas < 0) return this.emit("error", new Error(`Nu mai avem ${produs}`));
this.#stoc.set(produs, ramas);
this.emit("vanzare", produs, ramas);
if (ramas === 0) this.emit("stoc-epuizat", produs);
}
}
const m = new Magazin();
m.on("vanzare", (produs, ramas) => console.log(`Vândut: ${produs}, rămân ${ramas}`));
m.once("stoc-epuizat", (produs) => console.log(`Comandă nouă de ${produs}!`));
m.on("error", (e) => console.log("Eroare:", e.message));
m.vinde("mere");
m.vinde("mere");
m.vinde("mere");
Rezultat
Vândut: mere, rămân 1
Vândut: mere, rămân 0
Comandă nouă de mere!
Eroare: Nu mai avem mere
Exemplul 2: off și once
import { EventEmitter } from "node:events";
const sonerie = new EventEmitter();
const ana = () => console.log("Ana deschide ușa");
sonerie.on("suna", ana);
sonerie.once("suna", () => console.log("Câinele latră (doar prima dată)"));
sonerie.emit("suna");
sonerie.emit("suna");
sonerie.off("suna", ana);
console.log("Ascultători rămași:", sonerie.listenerCount("suna"));
console.log("emit fără ascultători:", sonerie.emit("suna"));
Rezultat
Ana deschide ușa
Câinele latră (doar prima dată)
Ana deschide ușa
Ascultători rămași: 0
emit fără ascultători: false
Exemplul 3: Așteptare cu await: events.once și events.on
import { EventEmitter, once, on } from "node:events";
const curier = new EventEmitter();
setTimeout(() => curier.emit("livrat", "Iași", "colet 77"), 10);
const [oras, colet] = await once(curier, "livrat");
console.log(`${colet} livrat în ${oras}`);
const ac = new AbortController();
setTimeout(() => {
for (const nota of [9, 10, 7]) curier.emit("nota", nota);
ac.abort();
}, 10);
try {
for await (const [nota] of on(curier, "nota", { signal: ac.signal })) console.log("Notă:", nota);
} catch (e) {
console.log(e.name);
}
Rezultat
colet 77 livrat în Iași
Notă: 9
Notă: 10
Notă: 7
AbortError
Greșeli frecvente
- Nu pui ascultător pentru
"error": un singuremit("error")oprește tot programul. - Scoți ascultătorul cu o funcție nouă:
off("x", () => ...)nu scoate nimic, pentru că este altă funcție. Păstrează referința dată laon. - Te aștepți ca
emitsă fie asincron: ascultătorii rulează imediat, înainte caemitsă se întoarcă.
Comenzi înrudite
stream.Readable: Stream-ul din care citești date bucată cu bucată: fișiere, cereri HTTP, stdin. Readable.from îl creează din orice iterabil.stream.pipeline: Leagă stream-uri în lanț (citire → transformare → scriere), cu tratarea erorilor și închiderea tuturor la final.http.createServer: Pornește un server web cu modulul de bază node:http: primești cererea (req) și trimiți răspunsul (res).timers/promises (setTimeout cu await): Variantele cu promisiuni ale temporizatoarelor: await setTimeout(1000) pentru o pauză, setInterval ca iterator asincron.