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:

  1. EventEmitter yaratib, greet hodisasiga obuna bo’ling va uni ism uzatib ikki marta e’lon qiling;
  2. Bitta hodisaga ikkita tinglovchi qo’shing va ular qaysi tartibda chaqirilishini kuzating;
  3. emit ni on dan oldin yozib ko’ring — hech nima chiqmasligiga ishonch hosil qiling;
  4. once bilan obuna bo’lib, hodisani uch marta e’lon qiling;
  5. OrderService klassini yozib, createOrder ichida created hodisasini e’lon qiling va ikkita tinglovchi bilan javob bering;
  6. Tinglovchisiz error hodisasini e’lon qilib dastur yiqilishini ko’ring, so’ng on("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.
  • on obuna qiladi, emit e’lon qiladi, once bir martalik obuna beradi, off bekor qiladi.
  • Tinglovchi emit dan oldin qo’shilishi kerak — hodisa saqlanmaydi.
  • off uchun nomlangan funksiya kerak: anonim arrow funksiyani o’chirib bo’lmaydi.
  • O’z klassingiz extends EventEmitter bilan hodisa e’lon qila oladi, constructor da super() majburiy.
  • Tinglovchisi yo’q error hodisasi 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.

Bu dars foydali bo'ldimi?

marta ko'rildi