8-bo‘lim
Hodisalar va EventEmitter
on va emit, once va off, argumentlar uzatish, error hodisasining maxsus xatti-harakati, sinfdan meros olish va xotira oqishi.
Ushbu bo‘lim mundarijasi
Node ning katta qismi hodisalar ustiga qurilgan: server so'rov kelganda hodisa chiqaradi, oqim ma'lumot kelganda hodisa chiqaradi.
Bu naqshning asosida EventEmitter sinfi turadi.
Birinchi tinglovchi #
import { EventEmitter } from "node:events";
const tugma = new EventEmitter();
tugma.on("bosildi", () => {
console.log("tugma bosildi");
});
tugma.emit("bosildi");
tugma.emit("bosildi");
console.log("Tinglovchilar:", tugma.listenerCount("bosildi"));
tugma bosildi
tugma bosildi
Tinglovchilar: 1
| Metod | Nima qiladi |
|---|---|
on(nom, f) | Tinglovchi qo'shadi |
emit(nom, ...) | Hodisani chiqaradi |
once(nom, f) | Faqat bir marta tinglaydi |
off(nom, f) | Tinglovchini olib tashlaydi |
listenerCount(nom) | Nechta tinglovchi bor |
Argument uzatish #
import { EventEmitter } from "node:events";
const buyurtma = new EventEmitter();
buyurtma.on("yaratildi", (id, mijoz, summa) => {
console.log(`#${id} - ${mijoz}: ${summa} so'm`);
});
buyurtma.emit("yaratildi", 1, "Malika", 125000);
buyurtma.emit("yaratildi", 2, "Husanboy", 340000);
#1 - Malika: 125000 so'm
#2 - Husanboy: 340000 so'm
emit ga bergan hamma argument tinglovchiga o'tadi.
once va off #
import { EventEmitter } from "node:events";
const server = new EventEmitter();
const izlar = [];
server.once("ishga-tushdi", () => izlar.push("bir marta"));
function doimiy() {
izlar.push("doimiy");
}
server.on("sorov", doimiy);
server.emit("ishga-tushdi");
server.emit("ishga-tushdi");
server.emit("sorov");
server.off("sorov", doimiy);
server.emit("sorov");
console.log(izlar.join(", "));
console.log("Qolgan tinglovchilar:", server.listenerCount("sorov"));
bir marta, doimiy
Qolgan tinglovchilar: 0
once - ishga tushishi bilan o'zini olib tashlaydi. Bu ishga
tushish yoki ulanish kabi bir martalik hodisalar uchun.
Hodisalar sinxron #
import { EventEmitter } from "node:events";
const emitter = new EventEmitter();
emitter.on("hodisa", () => console.log("2 - tinglovchi"));
console.log("1 - emit dan oldin");
emitter.emit("hodisa");
console.log("3 - emit dan keyin");
1 - emit dan oldin
2 - tinglovchi
3 - emit dan keyin
Bu juda ko'p chalkashtiriladi. emit - oddiy funksiya chaqiruvi.
U hamma tinglovchini o'sha zahoti, ketma-ket ishga tushiradi va
faqat shundan keyin emit dan qaytadi. Hech qanday navbat yoki
kechikish yo'q.
Demak: og'ir tinglovchi hodisalar siklini bloklaydi - 7-bo'limdagi qoida bu yerda ham amal qiladi.
Agar tinglovchi async bo'lsa, emit uning tugashini kutmaydi:
emitter.on("hodisa", async () => { await ish(); });
emitter.emit("hodisa"); // ish tugashini kutmaydi
Tugashini kutish kerak bo'lsa, EventEmitter noto'g'ri vosita -
oddiy async funksiya yoki vada ishlating.
Tartib - qo'shilish tartibi #
import { EventEmitter } from "node:events";
const e = new EventEmitter();
const izlar = [];
e.on("x", () => izlar.push("birinchi"));
e.on("x", () => izlar.push("ikkinchi"));
e.prependListener("x", () => izlar.push("oldinga qo'yilgan"));
e.emit("x");
console.log(izlar.join(" -> "));
oldinga qo'yilgan -> birinchi -> ikkinchi
Tinglovchilar qo'shilgan tartibda chaqiriladi.
prependListener esa eng oldinga qo'yadi.
error hodisasi maxsus #
import { EventEmitter } from "node:events";
const xavfsiz = new EventEmitter();
xavfsiz.on("error", (xato) => {
console.log("ushlandi:", xato.message);
});
xavfsiz.emit("error", new Error("ulanish uzildi"));
console.log("dastur davom etmoqda");
ushlandi: ulanish uzildi
dastur davom etmoqda
error - EventEmitter dagi yagona maxsus hodisa nomi.
Agar error chiqarilsa va uni hech kim tinglamayotgan bo'lsa,
Node xatoni tashlaydi va jarayon to'xtaydi:
Error: ulanish uzildi
at ...
Bu ataylab qilingan: e'tiborsiz qolgan xato jimgina yo'qolgandan ko'ra, dasturni to'xtatgani ma'qul.
Shuning uchun hodisa chiqaradigan har bir obyektga error
tinglovchisini qo'ying - server, oqim, soket. Bu Node dagi eng
ko'p uchraydigan kutilmagan qulash sababi.
O'z sinfingiz #
import { EventEmitter } from "node:events";
class Navbat extends EventEmitter {
#elementlar = [];
qosh(element) {
this.#elementlar.push(element);
this.emit("qoshildi", element, this.#elementlar.length);
return this;
}
ol() {
const element = this.#elementlar.shift();
if (element === undefined) {
this.emit("bosh");
return null;
}
return element;
}
}
const navbat = new Navbat();
navbat.on("qoshildi", (element, soni) => {
console.log(`qo'shildi: ${element} (jami ${soni})`);
});
navbat.on("bosh", () => console.log("navbat bo'sh"));
navbat.qosh("birinchi").qosh("ikkinchi");
console.log("olindi:", navbat.ol());
console.log("olindi:", navbat.ol());
navbat.ol();
qo'shildi: birinchi (jami 1)
qo'shildi: ikkinchi (jami 2)
olindi: birinchi
olindi: ikkinchi
navbat bo'sh
extends EventEmitter - o'z sinfingizga hodisa chiqarish imkonini
beradi. Node ning ichki sinflari ham aynan shunday yozilgan.
#elementlar - maxfiy maydon: sinfdan tashqarida unga murojaat
qilib bo'lmaydi.
Xotira oqishi ogohlantirishi #
import { EventEmitter } from "node:events";
const e = new EventEmitter();
console.log("Odatiy chegara:", e.getMaxListeners());
for (let i = 0; i < 5; i++) {
e.on("sorov", () => {});
}
console.log("Tinglovchilar:", e.listenerCount("sorov"));
e.setMaxListeners(20);
console.log("Yangi chegara:", e.getMaxListeners());
e.removeAllListeners("sorov");
console.log("Tozalangandan keyin:", e.listenerCount("sorov"));
Odatiy chegara: 10
Tinglovchilar: 5
Yangi chegara: 20
Tozalangandan keyin: 0
Bitta hodisaga 11-tinglovchi qo'shsangiz, Node shunday deydi:
MaxListenersExceededWarning: Possible EventEmitter memory leak
detected. 11 sorov listeners added.
Bu xato emas, ogohlantirish. U ko'pincha haqiqiy muammoni ko'rsatadi: kod tinglovchi qo'shyapti, lekin uni hech qachon olib tashlamayapti. Vaqt o'tib, tinglovchilar to'planib boradi va xotira o'sadi.
Yechim odatda setMaxListeners emas. Avval o'zingizdan
so'rang: "bu tinglovchilar qachon olib tashlanadi?" Ko'pincha
javob off yoki once bo'ladi.
Chegarani faqat haqiqatan ko'p tinglovchi kerak bo'lganda oshiring.
Vadaga aylantirish #
import { EventEmitter, once } from "node:events";
const yuklovchi = new EventEmitter();
setTimeout(() => yuklovchi.emit("tayyor", "ma'lumot keldi"), 10);
const [natija] = await once(yuklovchi, "tayyor");
console.log(natija);
console.log("await bilan kutildi");
ma'lumot keldi
await bilan kutildi
events modulidagi once funksiyasi (metod emas!) hodisani
vadaga aylantiradi.
Bu qayta chaqiruv uslubini async/await bilan aralashtirish
kerak bo'lganda juda qulay.
Asinxron takrorlash #
import { EventEmitter, on } from "node:events";
const kanal = new EventEmitter();
setTimeout(() => {
kanal.emit("xabar", "birinchi");
kanal.emit("xabar", "ikkinchi");
kanal.emit("xabar", "oxirgi");
}, 10);
const olingan = [];
for await (const [xabar] of on(kanal, "xabar")) {
olingan.push(xabar);
if (xabar === "oxirgi") break;
}
console.log(olingan.join(", "));
birinchi, ikkinchi, oxirgi
on funksiyasi hodisalarni asinxron ketma-ketlikka aylantiradi.
Diqqat: break yozmasangiz, sikl abadiy kutadi - hodisalar oqimi
o'z-o'zidan tugamaydi.
EventEmitteryaratib,onvaemitni sinang.- Hodisaga uchta argument uzating.
oncevaonfarqini ko'rsating.offbilan tinglovchini olib tashlang.emitsinxron ekanini isbotlang.- Uchta tinglovchi qo'shib, tartibini kuzating.
errorhodisasini tinglovchisiz chiqarib ko'ring.EventEmitterdan meros oluvchi sinf yozing.- O'n birta tinglovchi qo'shib, ogohlantirishni ko'ring.
events.oncebilan hodisaniawaitqiling.
Xulosa #
ontinglaydi,emitchiqaradi,oncebir marta,offolib tashlaydi.emitsinxron: tinglovchilar o'sha zahoti, ketma-ket ishlaydi vaemitularni kutmaydi.- Tinglovchilar qo'shilgan tartibda chaqiriladi.
- Tinglanmagan
errorhodisasi dasturni to'xtatadi - hodisa chiqaradigan har bir obyektgaerrortinglovchisi qo'ying. extends EventEmitterbilan o'z sinfingiz hodisa chiqara oladi.- O'ndan ortiq tinglovchi xotira oqishi ogohlantirishini beradi - sababini qidiring, chegarani oshirmang.
events.oncehodisani vadaga,events.onesa asinxron ketma-ketlikka aylantiradi.
Keyingi bo'limda oqimlarni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.