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.

🕑 13 daqiqa o‘qish 📄 548 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Birinchi tinglovchi
  2. Argument uzatish
  3. once va off
  4. Hodisalar sinxron
  5. Tartib - qo'shilish tartibi
  6. error hodisasi maxsus
  7. O'z sinfingiz
  8. Xotira oqishi ogohlantirishi
  9. Vadaga aylantirish
  10. Asinxron takrorlash
  11. Xulosa

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 #

JavaScript
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"));
Natija
tugma bosildi
tugma bosildi
Tinglovchilar: 1
MetodNima 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 #

JavaScript
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);
Natija
#1 - Malika: 125000 so'm
#2 - Husanboy: 340000 so'm

emit ga bergan hamma argument tinglovchiga o'tadi.

once va off #

JavaScript
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"));
Natija
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 #

JavaScript
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");
Natija
1 - emit dan oldin
2 - tinglovchi
3 - emit dan keyin
emit asinxron emas

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:

JavaScript
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 #

JavaScript
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(" -> "));
Natija
oldinga qo'yilgan -> birinchi -> ikkinchi

Tinglovchilar qo'shilgan tartibda chaqiriladi. prependListener esa eng oldinga qo'yadi.

error hodisasi maxsus #

JavaScript
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");
Natija
ushlandi: ulanish uzildi
dastur davom etmoqda
Tinglanmagan error dasturni o'ldiradi

error - EventEmitter dagi yagona maxsus hodisa nomi.

Agar error chiqarilsa va uni hech kim tinglamayotgan bo'lsa, Node xatoni tashlaydi va jarayon to'xtaydi:

Natija
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 #

JavaScript
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();
Natija
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 #

JavaScript
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"));
Natija
Odatiy chegara: 10
Tinglovchilar: 5
Yangi chegara: 20
Tozalangandan keyin: 0
O'nta tinglovchidan keyin ogohlantirish chiqadi

Bitta hodisaga 11-tinglovchi qo'shsangiz, Node shunday deydi:

Natija
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 #

JavaScript
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");
Natija
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 #

JavaScript
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(", "));
Natija
birinchi, ikkinchi, oxirgi

on funksiyasi hodisalarni asinxron ketma-ketlikka aylantiradi.

Diqqat: break yozmasangiz, sikl abadiy kutadi - hodisalar oqimi o'z-o'zidan tugamaydi.

Amaliy topshiriq
  1. EventEmitter yaratib, on va emit ni sinang.
  2. Hodisaga uchta argument uzating.
  3. once va on farqini ko'rsating.
  4. off bilan tinglovchini olib tashlang.
  5. emit sinxron ekanini isbotlang.
  6. Uchta tinglovchi qo'shib, tartibini kuzating.
  7. error hodisasini tinglovchisiz chiqarib ko'ring.
  8. EventEmitter dan meros oluvchi sinf yozing.
  9. O'n birta tinglovchi qo'shib, ogohlantirishni ko'ring.
  10. events.once bilan hodisani await qiling.

Xulosa #

  • on tinglaydi, emit chiqaradi, once bir marta, off olib tashlaydi.
  • emit sinxron: tinglovchilar o'sha zahoti, ketma-ket ishlaydi va emit ularni kutmaydi.
  • Tinglovchilar qo'shilgan tartibda chaqiriladi.
  • Tinglanmagan error hodisasi dasturni to'xtatadi - hodisa chiqaradigan har bir obyektga error tinglovchisi qo'ying.
  • extends EventEmitter bilan o'z sinfingiz hodisa chiqara oladi.
  • O'ndan ortiq tinglovchi xotira oqishi ogohlantirishini beradi - sababini qidiring, chegarani oshirmang.
  • events.once hodisani vadaga, events.on esa asinxron ketma-ketlikka aylantiradi.

Keyingi bo'limda oqimlarni o'rganamiz.

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.