Event Emitter
Muammodan boshlaylik
Foydalanuvchi ro'yxatdan o'tdi. Siz qilishingiz kerak:
- Xush kelibsiz email yuboring
- Analytics ga yozib qo'ying
- Admin ga xabar bering
Buni hammasini UsersService ichida yozish mumkin:
async register(dto: RegisterDto) {
const user = await this.create(dto);
await this.emailService.sendWelcome(user);
await this.analyticsService.track(user);
await this.notificationService.notifyAdmin(user);
return user;
}
Muammo: UsersService 3 ta boshqa servicega bog'liq. Har yangi talabda shu faylni o'zgartirish kerak. Modullar bir-biriga chirmashib ketdi.
Yechim — UsersService faqat "foydalanuvchi yaratildi" degan signal yuborsin, qolganlar o'zlari eshitsin.
Event Emitter nima?
Event Emitter — bitta joy event chiqaradi, boshqalar eshitadi. Chiqaruvchi va eshituvchi bir-birini bilmaydi.
Hayotiy o'xshatma
Radio stantsiya. Stantsiya kimga eshitayotganini bilmaydi — u faqat signal uzatadi. Eshitgisi kelganlar o'z radiopriyomnikini ulab qo'yadi.
UsersService Event Bus EmailService
│ │ │
│─ user.created ►│ │
│ │─ user.created ►│
│ │ │ sendWelcome()
O'rnatish
npm install @nestjs/event-emitter
// app.module.ts
import { EventEmitterModule } from '@nestjs/event-emitter';
@Module({
imports: [
EventEmitterModule.forRoot(),
],
})
export class AppModule {}
Fayl tuzilmasi
src/
users/
users.service.ts ← event chiqaradi
users.module.ts
email/
email.service.ts ← event eshitadi
email.module.ts
Event yuborish
// users/users.service.ts
import { EventEmitter2 } from '@nestjs/event-emitter';
@Injectable()
export class UsersService {
constructor(private eventEmitter: EventEmitter2) {}
async create(dto: CreateUserDto) {
const user = await this.userRepository.save(dto);
this.eventEmitter.emit('user.created', user); // ← signal chiqarildi
return user;
// UsersService email, analytics ni bilmaydi — bu uning ishi emas
}
}
Event eshitish (Listener)
// email/email.service.ts
import { OnEvent } from '@nestjs/event-emitter';
@Injectable()
export class EmailService {
@OnEvent('user.created') // ← shu signalni eshitadi
async handleUserCreated(user: User) {
await this.sendWelcomeEmail(user.email);
}
}
// analytics/analytics.service.ts
@Injectable()
export class AnalyticsService {
@OnEvent('user.created') // ← bir event — bir necha listener bo'lishi mumkin
async handleUserCreated(user: User) {
await this.track('new_registration', user.id);
}
}
Har ikkisi ham user.created ni eshitadi. UsersService ularni bilmaydi va bilmasligi kerak.
Async listener
// Default da listener sinxron ishlaydi.
// Async amallar uchun { async: true } qo'shing:
@OnEvent('user.created', { async: true })
async handleUserCreated(user: User) {
await this.sendEmail(user.email); // ← await ishlaydi
}
Qachon Event Emitter ishlatish kerak?
| Mos | Mos emas |
|---|---|
| Email, log, analytics (side-effect) | Asosiy biznes logika |
| Bir event — bir necha listener | Natija kerak bo'lsa (return) |
| Modullar orasida loosely coupled | So'rov-javob pattern |
Tez-tez uchraydigan xatolar
1. Listener ishlamayapti
Sababi: Listener joylashgan service o'z modulining providers ga qo'shilmagan.
Yechim: EmailModule providers da EmailService borligini tekshiring.
2. Async listener kutilmayapti
Sababi: { async: true } qo'yilmagan.
Yechim: @OnEvent('user.created', { async: true }) — async amallar uchun kerak.
Xulosa
- Event Emitter — modullar orasida loosely coupled aloqa
eventEmitter.emit('event.name', data)— event yuborish@OnEvent('event.name')— event eshitishUsersServiceemail/analytics ni bilmaydi — faqat signal chiqaradi- Side-effectlar uchun ideal (email, log, notification)
Keyingi dars: 45-dars: Scheduled Tasks — Cron Jobs