Node.js EventEmitter va hodisalar
Brauzerda tugma bosilishini addEventListener bilan kuzatgansiz.
Serverda tugma yo’q, lekin kuzatiladigan hodisalar bor: fayl o’qib
bo’lindi, mijoz ulandi, buyurtma yaratildi. Node.js’da bunday aloqani
EventEmitter tashkil qiladi.
Muammo: kim kimni chaqirishi kerak
Buyurtma yaratadigan funksiya yozdingiz. Buyurtma yaratilganda uch ish bajarilishi kerak: xat yuborish, jurnalga yozish, statistikani yangilash.
Eng sodda yechim — hammasini funksiya ichiga yozish:
function createOrder(id) {
console.log("Buyurtma yaratildi:", id);
// Keyin bu yerga yana va yana qo'shiladi
console.log("Xat yuborildi");
console.log("Jurnalga yozildi");
}
Muammo shundaki, createOrder endi hamma narsani biladi. Yangi ish
qo’shilsa, shu funksiya yana o’zgaradi.
EventEmitter boshqa yo’l taklif qiladi: funksiya faqat “buyurtma yaratildi” deb e’lon qiladi, kim javob berishini bilmaydi.
Birinchi hodisa
events — o’rnatilgan modul, npm install shart emas:
const EventEmitter = require("events");
const emitter = new EventEmitter();
// Hodisaga obuna bo'lamiz
emitter.on("greet", (name) => {
console.log("Salom,", name);
});
// Hodisani e'lon qilamiz
emitter.emit("greet", "Aziz");
emitter.emit("greet", "Dilnoza");
node emitter-demo.js
Salom, Aziz
Salom, Dilnoza
Ikki metod butun tizimning asosi:
| Metod | Vazifasi |
|---|---|
on(nom, funksiya) |
Hodisaga obuna bo’ladi |
emit(nom, ...qiymatlar) |
Hodisani e’lon qiladi |
emit ga berilgan qiymatlar tinglovchi funksiyaga argument bo’lib
o’tadi.
Bir nechta tinglovchi
Bitta hodisaga istagancha tinglovchi qo’shiladi — ular qo’shilgan tartibda chaqiriladi:
const EventEmitter = require("events");
const emitter = new EventEmitter();
emitter.on("orderCreated", (order) => {
console.log("Xat yuborildi:", order.id);
});
emitter.on("orderCreated", (order) => {
console.log("Jurnalga yozildi:", order.id);
});
emitter.emit("orderCreated", { id: 7, total: 50000 });
Xat yuborildi: 7
Jurnalga yozildi: 7
Yangi ish qo’shish uchun emit yozilgan joyga tegilmaydi — yana bitta
on qo’shiladi.
once — faqat bir marta
once bilan obuna bo’lgan tinglovchi birinchi hodisadan keyin o’zini
o’chiradi:
const EventEmitter = require("events");
const emitter = new EventEmitter();
emitter.once("start", () => {
console.log("Dastur ishga tushdi");
});
emitter.emit("start");
emitter.emit("start");
emitter.emit("start");
Dastur ishga tushdi
Uch marta e’lon qilindi, bir marta bajarildi. Bu ishga tushirish, ulanish o’rnatish kabi bir martalik ishlar uchun qulay.
off — obunani bekor qilish
Obunani bekor qilish uchun tinglovchi funksiyaning nomi kerak:
const EventEmitter = require("events");
const emitter = new EventEmitter();
function handleData(value) {
console.log("Qabul qilindi:", value);
}
emitter.on("data", handleData);
emitter.emit("data", 1);
emitter.off("data", handleData);
emitter.emit("data", 2);
console.log("Qolgan tinglovchi:", emitter.listenerCount("data"));
Qabul qilindi: 1
Qolgan tinglovchi: 0
Ikkinchi emit hech nima chiqarmadi — obuna bekor qilingan edi.
O’z klassingizni meros qilish
Amalda new EventEmitter() kamdan-kam ishlatiladi. Ko’pincha o’z
klassingiz EventEmitter’dan meros oladi:
const EventEmitter = require("events");
class OrderService extends EventEmitter {
constructor() {
super();
this.orders = [];
}
createOrder(id, total) {
const order = { id, total };
this.orders.push(order);
// Ish bajarildi — endi e'lon qilamiz
this.emit("created", order);
return order;
}
}
const orderService = new OrderService();
orderService.on("created", (order) => {
console.log(`Buyurtma ${order.id} yaratildi, summa: ${order.total}`);
});
orderService.on("created", (order) => {
console.log("Statistika yangilandi, jami:", orderService.orders.length);
});
orderService.createOrder(7, 50000);
orderService.createOrder(8, 120000);
Buyurtma 7 yaratildi, summa: 50000
Statistika yangilandi, jami: 1
Buyurtma 8 yaratildi, summa: 120000
Statistika yangilandi, jami: 2
Klasslar va meros
darslaridagi extends hamda super() shu yerda ishga tushdi.
error hodisasi nega maxsus
error — EventEmitter’da alohida munosabatdagi nom.
Tinglovchisi bo’lmagan error hodisasi e’lon qilinsa, dastur
yiqiladi:
const EventEmitter = require("events");
const emitter = new EventEmitter();
emitter.emit("error", new Error("Ulanish uzildi"));
console.log("Bu qator bajarilmaydi");
node:events:486
throw er; // Unhandled 'error' event
^
Error: Ulanish uzildi
at Object.<anonymous> (D:\node-start\emitter-demo.js:5:24)
Oxirgi console.log chiqmadi. Dastur to’xtadi va chiqish kodi 1
bo’ldi.
Tinglovchi qo’shilsa, holat butunlay o’zgaradi:
const EventEmitter = require("events");
const emitter = new EventEmitter();
emitter.on("error", (error) => {
console.log("Ushlandi:", error.message);
});
emitter.emit("error", new Error("Ulanish uzildi"));
console.log("Dastur davom etmoqda");
Ushlandi: Ulanish uzildi
Dastur davom etmoqda
Node.js ichida qayerda ishlatiladi
EventEmitter — Node.js’ning o’zida keng ishlatiladigan asos. Siz uni bilmasdan ham allaqachon ishlatgansiz:
| Qayerda | Hodisalar |
|---|---|
| HTTP server | request, close |
| Fayl oqimlari | data, end, error |
process obyekti |
exit, uncaughtException |
process ham EventEmitter — buni tekshirish mumkin:
process.on("exit", (code) => {
console.log("Dastur tugadi, kod:", code);
});
console.log("Asosiy ish bajarilmoqda");
Asosiy ish bajarilmoqda
Dastur tugadi, kod: 0
process darsida ko’rgan obyektingiz hodisa ham e’lon qilar ekan.
Xotira sizishi ogohlantirishi
Bitta hodisaga 10 tadan ortiq tinglovchi qo’shsangiz, Node.js ogohlantiradi:
MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
11 tick listeners added to [EventEmitter]. MaxListeners is 10.
Bu xato emas — dastur ishlayveradi. Lekin sabab odatda haqiqiy muammo:
on sikl ichida yoki har so’rovda chaqirilib, tinglovchilar to’planib
qolgan bo’ladi.
Amaliy mashq
node-start papkasida bajaring:
EventEmitteryaratib,greethodisasiga obuna bo’ling va uni ism uzatib ikki marta e’lon qiling;- Bitta hodisaga ikkita tinglovchi qo’shing va ular qaysi tartibda chaqirilishini kuzating;
emitniondan oldin yozib ko’ring — hech nima chiqmasligiga ishonch hosil qiling;oncebilan obuna bo’lib, hodisani uch marta e’lon qiling;OrderServiceklassini yozib,createOrderichidacreatedhodisasini e’lon qiling va ikkita tinglovchi bilan javob bering;- Tinglovchisiz
errorhodisasini e’lon qilib dastur yiqilishini ko’ring, so’ngon("error", ...)qo’shib xatoni ushlang.
6-qadam eng muhimi: error hodisasining maxsus xatti-harakati keyingi
darsdagi oqimlarda to’g’ridan-to’g’ri kerak bo’ladi.
Qisqacha xulosa
- EventEmitter e’lon qiluvchi bilan tinglovchini bir-biridan ajratadi: ikkalasi bir-birini bilmaydi.
onobuna qiladi,emite’lon qiladi,oncebir martalik obuna beradi,offbekor qiladi.- Tinglovchi
emitdan oldin qo’shilishi kerak — hodisa saqlanmaydi. offuchun nomlangan funksiya kerak: anonim arrow funksiyani o’chirib bo’lmaydi.- O’z klassingiz
extends EventEmitterbilan hodisa e’lon qila oladi,constructordasuper()majburiy. - Tinglovchisi yo’q
errorhodisasi dasturni yiqitadi — uni har doim ushlang. - 10 tadan ortiq tinglovchi ogohlantirish beradi: odatda bu takroran qo’shilgan obunadan darak.
Keyingi darsda oqimlar — katta faylni xotirani to’ldirmasdan qayta ishlash.