JavaScript 이벤트 기반 통신 구조 분석
이벤트 기반 통신은 발행자와 구독자가 중개자 역할을 하는 이벤트 채널을 통해 상호작용하는 아키텍처입니다. 발행자는 이벤트를 직접 수신자에게 전달하지 않고, 특정 카테고리로 분류된 메시지를 채널에 등록합니다. 수신자는 관심 있는 이벤트 유형만 필터링하여 처리합니다.
핵심 구성 요소:
- 발행자(Producer): 이벤트를 생성하는 소스
- 구독자(Consumer): 특정 이벤트에 반응하는 리스너
- 이벤트 중개자(Event Mediator): 이벤트 관리 및 전달 로직
- 토픽(Topic): 이벤트의 분류 식별자
기초 구현 예제
class EventBus {
constructor() {
// 이벤트-콜백 매핑 { event: [handler1, handler2] }
this.handlers = new Map();
}
// 이벤트 구독
on(event, callback) {
if (!this.handlers.has(event)) {
this.handlers.set(event, []);
}
this.handlers.get(event).push(callback);
// 구독 해지 함수 반환
return () => this.off(event, callback);
}
// 이벤트 발행
emit(event, payload) {
if (!this.handlers.has(event)) return;
this.handlers.get(event).forEach(cb => cb(payload));
}
// 구독 해지
off(event, callback) {
if (!this.handlers.has(event)) return;
this.handlers.get(event) = this.handlers.get(event).filter(cb => cb !== callback);
}
}
사용 사례
// 인스턴스 생성
const eventBus = new EventBus();
// 구독자1: 'news' 이벤트 처리
const removeSubscription1 = eventBus.on('news', data => {
console.log(`구독자1: ${data.title} - ${data.content}`);
});
// 구독자2: 'news' 이벤트 처리
eventBus.on('news', data => {
console.log(`구독자2: ${data.title}`);
});
// 구독자3: 'weather' 이벤트 처리
eventBus.on('weather', data => {
console.log(`날씨 알림: ${data}`);
});
// 이벤트 발행
eventBus.emit('news', {
title: "JavaScript 최신 기능 공개",
content: "ES2023에서 Array.findLast() 추가"
});
// 출력:
// 구독자1: JavaScript 최신 기능 공개 - ES2023에서 Array.findLast() 추가
// 구독자2: JavaScript 최신 기능 공개
eventBus.emit('weather', "서울: 흐린 날, 22℃");
// 출력: 날씨 알림: 서울: 흐린 날, 22℃
// 구독자1 해지
removeSubscription1();
// 재발행 시 구독자2만 수신
eventBus.emit('news', { title: "구독 해지 테스트" });
// 출력: 구독자2: 구독 해지 테스트
주요 기능 분석
- 결합도 제어
- 발행자와 구독자 간 직접적 의존성 제거
- 구독자 단독으로 관심 이벤트 탐색 가능
- 동적 관계 관리
- 실행 중 구독자 추가/삭제 지원
- 다중 구독자 동시 처리 가능
- 적용 분야
- 컴포넌트 간 비상속 통신 (Vue/React)
- 마이크로서비스 간 메시징
- 플러그인 시스템 이벤트 트리거
고급 확장 방향
// 1. silde 패턴 지원
on('user.*', handler) // user.create/user.delete 등 모든 하위 이벤트 수신
// 2. 비동기 처리
async emit(event, payload) {
const handlers = this.handlers.get(event) || [];
await Promise.all(handlers.map(h => h(payload)));
}
// 3. 컨텍스트 관리
on(event, handler, context) {
const wrapped = () => handler.apply(context);
// ...wrapped 저장
}
// 4. 일회성 구독
once(event, handler) {
const unsub = this.on(event, data => {
handler(data);
unsub();
});
}
관찰자 패턴과 차이점
| 특성 | 이벤트 기반 | 관찰자 패턴 |
|---|---|---|
| 결합도 | 완전 분리(채널 통한) | 느슨한 결합(목록 직접 관리) |
| 통신 방식 | 이벤트 기반 | 직접 알림 |
| 관계 구조 | 다대다 | 일반적으로 다대일 |
핵심 차이: 이벤트 기반은 별도 중개자 존재, 관찰자 패턴은 주제가 직접 관찰자 목록 관리
실무에서는 다음 라이브러리 권장:
- EventEmitter3 (Node.js/브라우저)
- RxJS (반응형 프로그래밍)
- Vue의
EventBus/ React의 세 번째 파티 라이브러리