event 사용하기


node.js 는 이벤트 기반 비동기 방식의 서버프레임웍입니다. 이번장에서는 node.js 의 핵심이랄 수 있는 이벤트 처리에 대해서 알아보겠습니다.

먼저 이벤트를 이해하기 위해서는 이벤트를 생성하고, 연결한 후, 이벤트를 발생시켜서 연결된 로직을 실행하는 기본 기능들을 알아야만 하는데 node.js 에서는 기본적으로 아래의 세가지 함수와 객체를 이용해서 이벤트 처리를 하게됩니다.

  • EventEmitter : node.js 의 모든 이벤트처리가 정의된 기본객체입니다. 이벤트를 사용하기 위해서는 이 객체를 재정의해서 사용해야할 수 있습니다.
  • on( ) : 이벤트를 연결하는 함수입니다. 이전장에서 request 객체에 on( ) 함수를 이용해서 'data'라는 이벤트를 캐치해서 사용했었는데 모든 이벤트처리는 이런 동일한 루틴을 거쳐서 사용하게 됩니다.
  • emit( ) : 이벤트를 발생시키는 함수입니다. 위의 on( ) 함수에서 'data'라는 이벤트가 캐치되기 위해서는 emit('data') 의 형태로 이벤트를 발생시켜야 합니다.

가. 이벤트를 가진 객체 만들기

node.js 에서 이벤트는 events라는 내장모듈에 정의 되어 있습니다. 아래 예제에서는 events 모듈을 재정의 해서 새로운 객체를 생성한 후 사용해 보겠습니다. 먼저 custom_event.js 파일을 생성하고 아래와 같이 입력합니다.

  • custom_event.js
// 1. 이벤트가 정의되 있는 events 모듈 생성. 이전 버전의 process.EventEmitter() 는 deprecated!
var EventEmitter = require('events');

// 2. 생성된 이벤트 모듈을 사용하기 위해 custom_object로 초기화
var custom_object = new EventEmitter();

// 3. events 모듈에 선언되어 있는 on( ) 함수를 재정의 하여 'call' 이벤트를 처리 
custom_object.on('call', ()=> {
    console.log('called events!');
});

// 4. call 이벤트를 강제로 발생
custom_object.emit('call');

node custom_event 를 실행하면 아래와 같이 출력되는 것을 확인할 수 있습니다.

이번에는 매초 이벤트를 이용해서 콘솔상에 주기적으로 현재시간을 출력하는 타이머 모듈을 만들고 사용해보겠습니다.

프로젝트 폴더에 custom_module_timer.js와 call_timer.js 파일을 생성하고 아래와 같이 입력합니다.

  • custom_module_timer.js
var EventEmitter = require('events');
// 1. setInterval 함수가 동작하는 interval 값을 설정합니다. 1초에 한번씩 호출
var sec = 1;

// 2. timer변수를 EventEmitter 로 초기화
exports.timer = new EventEmitter();

// 3. javascript 내장함수인 setInterval 을 사용해서 1초에 한번씩 timer 객체에 tick 이벤트 발생
setInterval(function(){
    exports.timer.emit('tick');
}, sec*1000);
  • call_timer.js
var module = require('./custom_module_timer');

// 1. module 내부에 선언된 timer객체를 통해 tick 이벤트를 캐치하고, 이벤트 발생시마다 현재시간을 출력
module.timer.on('tick', function(time){
    var time = new Date(); // 2. 현재 시간을 가져오기 위한 Date 객체 생성
    console.log('now:'+time);
});

node call_timer 로 실행하면 아래와 같이 콘솔상에 매초마다 현재 시간을 출력해줍니다.

이렇게 setInterval( ) 함수를 사용해서 이벤트 처리를 해보았습니다. 위의 예제에서는 단순하게 events 모듈을 그대로 사용해보았지만 객체지향에서처럼 EventEmitter 객체를 상속한 후 재정의 할 수도 있습니다.

나. request 객체로 보는 이벤트처리

아래는 부록의 http request 객체 로그의 일부 입니다. 로그의 중간 부분에 보면 아래와 같이 _events 로 각각의 이벤트명이 정의되어 있습니다. 이전장에서 사용했던 end, data 등의 이름도 보이는데 request 객체는 이렇게 events 모듈을 재정의해서 구현되어 있기 때문에 우리가 단순하게 on('end') 형태로 이벤트를 호출만 해도 사용할 수 있는 것입니다.

--- request 객체 로그 일부 ---
...
     _events:
      { end: [Object],
        finish: [Function: onSocketFinish],
        _socketEnd: [Function: onSocketEnd],
        drain: [Object],
        timeout: [Function],
        error: [Function: socketOnError],
        close: [Object],
        data: [Function: socketOnData],
        resume: [Function: onSocketResume],
        pause: [Function: onSocketPause] },
...

이렇게 node.js 에서 event 처리는 events 모듈을 재정의 해서 만들어지게 되는데, 어떤 요청에 대해 event 를 사용해서 비동기 처리를 하게되면, 단일요청에 대한 thread 대기시간이 없어지기 때문에 동기처리에 비해 프로세스를 좀 더 효율적으로 사용할 수 있습니다.

단점으로 지적되는 비동기로 인한 callback 이벤트의 개수가 많아지면 로직상의 가독성이 떨어지는 면이 있지만, 그걸 감안하더라도 성능면에서는 기존 multi-thread 동기 방식에 비해 진보된 형태의 서버 아키텍처라고 말할 수 있을것 같습니다.

results matching ""

    No results matching ""