728x90
반응형
1. EventEmitter란
EventEmitter는 Node.js에서 이벤트 기반 프로그래밍을 구현하기 위한 핵심 클래스입니다. 이벤트를 발생시키고(emit) 리스너를 등록하여(on) 느슨하게 결합된 비동기 아키텍처를 구축할 수 있습니다. http, fs, stream 등 대부분의 Node.js 핵심 모듈이 EventEmitter를 기반으로 합니다.
2. EventEmitter 생성
const EventEmitter = require('events');
// 방법 1: 직접 인스턴스 생성
const emitter = new EventEmitter();
// 방법 2: 클래스 상속
class MyEmitter extends EventEmitter {
constructor() {
super();
this.name = 'MyEmitter';
}
}
const myEmitter = new MyEmitter();
3. 이벤트 등록과 발생
3.1 on()과 emit()
const EventEmitter = require('events');
const emitter = new EventEmitter();
// 이벤트 리스너 등록
emitter.on('message', (data) => {
console.log('메시지 수신:', data);
});
// 여러 인자 전달
emitter.on('user', (name, age, city) => {
console.log(`${name}, ${age}세, ${city}`);
});
// 이벤트 발생
emitter.emit('message', 'Hello World');
// 메시지 수신: Hello World
emitter.emit('user', '홍길동', 30, '서울');
// 홍길동, 30세, 서울
3.2 addListener() (on의 별칭)
// on()과 동일
emitter.addListener('event', () => {
console.log('이벤트 발생');
});
3.3 once() - 일회성 리스너
emitter.once('connect', () => {
console.log('연결됨 (한 번만 실행)');
});
emitter.emit('connect'); // 연결됨 (한 번만 실행)
emitter.emit('connect'); // 아무 일도 없음
3.4 prependListener() - 리스너 맨 앞에 추가
emitter.on('data', () => console.log('리스너 1'));
emitter.on('data', () => console.log('리스너 2'));
emitter.prependListener('data', () => console.log('리스너 0'));
emitter.emit('data');
// 리스너 0
// 리스너 1
// 리스너 2
4. 리스너 제거
4.1 off() / removeListener()
function handler(data) {
console.log('데이터:', data);
}
emitter.on('data', handler);
emitter.emit('data', 'test'); // 데이터: test
emitter.off('data', handler);
// 또는 emitter.removeListener('data', handler);
emitter.emit('data', 'test'); // 아무 출력 없음
4.2 removeAllListeners()
emitter.on('event', () => console.log('1'));
emitter.on('event', () => console.log('2'));
emitter.on('other', () => console.log('other'));
// 특정 이벤트의 모든 리스너 제거
emitter.removeAllListeners('event');
// 모든 이벤트의 모든 리스너 제거
emitter.removeAllListeners();
5. 이벤트 정보 조회
const emitter = new EventEmitter();
emitter.on('data', () => {});
emitter.on('data', () => {});
emitter.on('error', () => {});
// 이벤트 이름 목록
console.log(emitter.eventNames());
// ['data', 'error']
// 특정 이벤트의 리스너 수
console.log(emitter.listenerCount('data'));
// 2
// 특정 이벤트의 리스너 배열
console.log(emitter.listeners('data'));
// [Function, Function]
// 원본 리스너 (once로 등록해도 래핑되지 않은 원본)
console.log(emitter.rawListeners('data'));
반응형
6. 에러 처리
error 이벤트는 특별하게 처리됩니다. 리스너가 없으면 예외가 발생하고 프로세스가 종료됩니다.
const emitter = new EventEmitter();
// error 리스너 없이 emit하면 예외 발생
// emitter.emit('error', new Error('문제 발생'));
// → 프로세스 종료
// error 리스너 등록
emitter.on('error', (err) => {
console.error('에러 처리:', err.message);
});
emitter.emit('error', new Error('문제 발생'));
// 에러 처리: 문제 발생 (프로세스 계속 실행)
7. 리스너 수 제한
기본적으로 이벤트당 10개의 리스너 제한이 있습니다. 메모리 누수 방지를 위한 설정입니다.
const emitter = new EventEmitter();
// 현재 최대 리스너 수 확인
console.log(emitter.getMaxListeners()); // 10
// 최대 리스너 수 변경
emitter.setMaxListeners(20);
// 전역 기본값 변경
EventEmitter.defaultMaxListeners = 15;
// 무제한 (권장하지 않음)
emitter.setMaxListeners(0);
// 또는
emitter.setMaxListeners(Infinity);
8. 비동기 이벤트 처리
8.1 async 리스너
const emitter = new EventEmitter();
emitter.on('fetch', async (url) => {
try {
const response = await fetch(url);
const data = await response.json();
emitter.emit('success', data);
} catch (err) {
emitter.emit('error', err);
}
});
emitter.on('success', (data) => {
console.log('성공:', data);
});
emitter.on('error', (err) => {
console.error('실패:', err.message);
});
emitter.emit('fetch', 'https://api.example.com/data');
8.2 events.on() - 비동기 이터레이터
const { on } = require('events');
async function processEvents(emitter) {
for await (const [data] of on(emitter, 'data')) {
console.log('받은 데이터:', data);
if (data === 'end') break;
}
}
const emitter = new EventEmitter();
processEvents(emitter);
emitter.emit('data', '첫 번째');
emitter.emit('data', '두 번째');
emitter.emit('data', 'end');
8.3 events.once() - Promise 반환
const { once } = require('events');
async function waitForConnect(emitter) {
const [connection] = await once(emitter, 'connect');
console.log('연결됨:', connection);
}
const emitter = new EventEmitter();
waitForConnect(emitter);
setTimeout(() => {
emitter.emit('connect', { host: 'localhost', port: 3000 });
}, 1000);
9. 실전 예시: 커스텀 클래스
const EventEmitter = require('events');
class TaskQueue extends EventEmitter {
constructor() {
super();
this.tasks = [];
this.running = false;
}
add(task) {
this.tasks.push(task);
this.emit('taskAdded', task);
if (!this.running) {
this.process();
}
}
async process() {
this.running = true;
this.emit('start');
while (this.tasks.length > 0) {
const task = this.tasks.shift();
this.emit('taskStart', task);
try {
const result = await task();
this.emit('taskComplete', { task, result });
} catch (err) {
this.emit('taskError', { task, error: err });
}
}
this.running = false;
this.emit('empty');
}
}
// 사용
const queue = new TaskQueue();
queue.on('taskAdded', (task) => console.log('작업 추가됨'));
queue.on('taskStart', (task) => console.log('작업 시작'));
queue.on('taskComplete', ({ result }) => console.log('완료:', result));
queue.on('taskError', ({ error }) => console.error('에러:', error.message));
queue.on('empty', () => console.log('모든 작업 완료'));
queue.add(async () => {
await new Promise(r => setTimeout(r, 100));
return '작업 1 결과';
});
queue.add(async () => {
await new Promise(r => setTimeout(r, 100));
return '작업 2 결과';
});
10. captureRejections 옵션
async 리스너의 에러를 자동으로 error 이벤트로 전달합니다.
const emitter = new EventEmitter({ captureRejections: true });
emitter.on('event', async () => {
throw new Error('비동기 에러');
});
emitter.on('error', (err) => {
console.error('캡처된 에러:', err.message);
});
emitter.emit('event');
// 캡처된 에러: 비동기 에러
결론
EventEmitter는 Node.js 이벤트 기반 아키텍처의 핵심입니다. on/emit으로 이벤트를 등록하고 발생시키며, once로 일회성 리스너를 등록합니다. error 이벤트는 반드시 처리해야 하고, 클래스 상속을 통해 커스텀 이벤트 기반 객체를 만들 수 있습니다. events.once()와 events.on()을 활용하면 Promise 기반으로 더 깔끔하게 이벤트를 처리할 수 있습니다.
728x90
반응형
'Node.js' 카테고리의 다른 글
| Node.js의 타이머 함수(Timer Functions) (0) | 2026.02.25 |
|---|---|
| Node.js의 콘솔 객체(console object) (0) | 2026.02.25 |
| Node.js의 프로세스 객체(process object) (0) | 2026.02.25 |
| Node.js의 글로벌 객체(Global Objects) (0) | 2026.02.24 |
| Node.js의 버퍼(Buffer) 사용법 (0) | 2026.02.24 |