Node.js|EventEmitterの使い方解説

この投稿は、弊社が提供するWESEEK TECH通信の一環です。
WESEEK TECH通信とは、WESEEKのエンジニアがキャッチアップした技術に関する情報を、techブログを通じて定期的に発信していくものです。

はじめに

こんにちは、システムエンジニアの かおり です。本記事では、Node.jsのEventEmitterについてお話します。この記事で取り上げる内容は以下になります。

Event Emitter とは

何かのイベントが発生した時に、それがトリガーとなって、あらかじめ登録しておいた処理を実行することができます。

Event Emitter の作成

Event Emitterを作成するには、Node.jsのeventsモジュールからEventEmitterインスタンスを生成する必要があります。

const EventEmitter = require('events');
const myEmitter = new EventEmitter(); // EventEmitterインスタンスを生成

イベントの発動と、それに対応する処理

Event Emitterの基本的な使い方として、on()emit()関数についてお話します。

  • on(eventName , listener )
    第一引数に指定したイベントに紐づけて、listenerを登録します。

  • emit(eventName , [args])
    この関数でイベントが発動し、第二引数以降のargsを引数として渡します。

emit()関数でイベントが発動し、on()関数で登録されていた処理が実行されます。

import { EventEmitter } from 'events';
const eventEmitter = new EventEmitter();

// イベントが発動された時の処理を記述する
eventEmitter.on('myEvent', () => {
    console.log('Emitted Event');
});

// イベントを発動させる
eventEmitter.emit('myEvent');

上記のコードが実行された時に、以下のように出力されます。

> Emitted Event

on()を使って登録されたlistenerは、そのイベントが発火される度に実行されます。

同期か非同期か

Event Emitterによって発生したイベントは、同期的に実行されます。

import { EventEmitter } from 'events';
const eventEmitter = new EventEmitter();

eventEmitter.on('myEvent', (data) => {
    console.log(data);
});

console.log('A');
eventEmitter.emit('myEvent', 'B');
console.log("C"); 

上記のコードを実行した場合、以下のように上から順番に出力されます。

> A
> B
> C

listenerの実行順序

EventEmitterによって発生したイベントは、登録された全てのlistenerが順番に実行されます

import { EventEmitter } from 'events';
const eventEmitter = new EventEmitter();

eventEmitter.on('myEvent', (data) => {
    console.log(data, 'FIRST');
});

console.log('A');

eventEmitter.on("myEvent", data => {
    console.log(data, 'SECOND');
});

// イベントの発動
eventEmitter.emit('myEvent', 'Emitted Statement:');

console.log("B");

上記のコードが実行された場合、以下のように出力されます。

> A
> Emitted Statement: FIRST
> Emitted Statement: SECOND
> B

ある特定のイベントに対して反応させるには、同じEventEmitterインスタンスからemitを実行する必要がある

on()で登録したイベントハンドラをトリガーするには、同じEventEmitterインスタンスのemit()を呼び出す必要があります。

以下のコードでは、別のEventEmitterインスタンスが使用されているため、コンソールには何も出力されません。

import { EventEmitter } from 'events';

const eventEmitter1 = new EventEmitter();
eventEmitter1.on('myEvent', () => {
    console.log('myEvent emitted');
});

const eventEmitter2 = new EventEmitter();
eventEmitter2.emit('myEvent');

実際の利用時には複数のEventEmitterインスタンスを使うことは稀だと思いますが、イベントが伝播しない等の症状が起こった場合はこの辺りも疑ってみましょう。

Event Emitter クラスの関数

EventEmitterクラスの中で、on() emit()以外の関数を取り上げます。

  • once(eventName, listener)
    listenerを一度だけ実行したい場合に使用されます。
    このメソッドを使用すると、イベントをリッスンした後に、listenerが破棄されます。

  • addListener(eventName, listener)
    これはon()のエイリアスです。

  • removeListener(eventName, listener)
    これは、listenerを削除するために使用されます。

  • removeAllListeners([eventName])
    これは、 eventName に登録されている全ての listener を取り除きます。

Event Emitter の使い所

弊社で開発中のナレッジ共有サービス「GROWI」を例に出して説明します。
GROWIでは、ページにコメントが追加された時にDBにコメントのドキュメントが保存されます。

DBにデータが保存されたタイミングで特定の処理をしたい時には、Modelスキーマが提供するpost save hookを利用して実行することができます。

ただし、注意点として、モデルからサービス層などで定義された関数を直接呼び出すのはアーキテクチャの設計的によくありません。

そこで、post save hookにてEventEmitterでイベントを発火、それをサービス層で検知して登録していた処理を実行させることができます。

React ✖️ EventEmitter

Reactで状態管理にEventEmitterを使用する
以下の記事が参考になりますので、よければチェックしてみてください。

まとめ

EventEmitterは

  • 何かしらのイベントをトリガーとして、処理を実行する
  • イベントに登録されているlistenerを同期的に呼び出す
  • イベントに登録されているlistenerを登録された順番に呼び出す

いかがでしたでしょうか。
最後まで読んでくださりありがとうございました!

参考にさせていただいた記事