Node.js에서 사용되는 중요하고 기본적인 패턴은 관찰자 패턴이다. 리액터, 콜백 그리고 모듈과 함께 관찰자 패턴은 플랫폼의 핵심 중 하나이며, 많은 Node 코어와 사용자 영역 모듈을 사용하는데 있어 필수적인 조건이다. 관찰자 패턴은 Node.js의 반응적인 특성을 모델링하고 콜백을 완벽하게 보완하는 이상적인 해결책이다.
관찰자 패턴은 상태 변화가 일어날 때 관찰자에게 알릴 수 있는 객체를 정의하는 것이다
콜백 패턴과의 가장 큰 차이점은 Subject가 실제로 여러 관찰자들에게 알릴 수 있다는 것이다. 전통적인 연속 전달 스타일 콜백은 일반적으로 그 결과를 하나의 콜백에게만 전달한다.
전통적인 객체지향 프로그래밍에서 관찰자 패턴에는 인터페이스와 구현된 클래스들 그리고 계층 구조가 필요하다. 관찰자 패턴은 이미 코어에 내장되어 있고 EventEmitter 클래스를 사용하여 특정 유형의 이벤트가 발생되면 호출될 하나 이상의 함수를 리스너로 등록 할 수 있다.
EventEmitter는 프로토타입이며 코어 모듈로부터 익스포트 된다. 다음 코드는 EventEmitter에 대한 참조를 얻을 수 있는 방법을 보여준다.
const EventEmitter = require('events').EventEmitter;
const eeInstacne = new EventEmitter();
EventEmitter의 필수 메소드는 다음과 같다.
위의 모든 메소드들은 연결을 가능하게 하기 위해 EventEmitter 인스턴스를 반환하는데, listener 함수는 시그니처 함수([arg], [..])를 가지고 있기 때문에 이벤트가 발생된 순간에 전달되는 인수들을 쉽게 받아 들일 수 있다. listener 내부에서는 이벤트를 생성하는 EventEmitter의 인스턴스를 참조한다. 이는 전통적인 node.js의 콜백과는 다르게 항상 첫번째 인자가 error일 필요가 없으며 emit()이 호출될 때 전달된 어떤 값이든 가능하다.
const EventEmitter = require('events').EventEmitter;
const fs = require('fs');
function findPattern(files, regex) {
const emitter = new EventEmitter();
files.forEach( (file) => {
fs.readFile(file, 'utf-8', (err, content) => {
if(err)
return emitter.emit('error', err);
emitter.emit('fileread, file');
let match;
if(match == content.match(regex))
match.forEach(ele => emitter.emit('found', file, elem))
})
})
}
위 함수는 EventEmitter 사용하여 파일 목록에서 특정 패턴이 발견되면 실시간으로 구독자들에게 알리는 함수이다. EventEmitter로 만든 위 함수는 세 가지 이벤트를 생성하는데 다음과 같다