Node.jsで独自クラスにイベント機能を組み込む

Node.js のコアはイベントループによって動いているため、業務ロジックを持つ独自クラスでも「何かが起きたら通知したい」という要求が頻繁に出る。events モジュールに含まれる EventEmitter を継承すれば、簡単にその要求を満たせる。

EventEmitter の主な API

メソッド用途
addListener(name, fn)イベント名に対してコールバックを登録
on(name, fn)addListener のエイリアス
once(name, fn)初回のみ実行されるリスナーを登録
removeListener(name, fn)特定のリスナーを削除
listeners(name)登録済みリスナーの配列を取得
setMaxListeners(n)最大リスナー数を制限(デフォルト 10)

独自クラスに EventEmitter を継承させる

ES6 以降では class extends を使えば簡潔に書けるが、従来のプロトタイプベースでも問題ない。

const { EventEmitter } = require('events');

function Wallet(initial = 0) {
  EventEmitter.call(this);      // コンストラクタ借用
  this.amount = initial;
}
Wallet.prototype = Object.create(EventEmitter.prototype);
Wallet.prototype.constructor = Wallet;

Wallet.prototype.income = function (value) {
{
  this.amount += value;
  this.emit('moneyChanged', this.amount);
};

Wallet.prototype.outgo = function (value) {
  this.amount -= value;
  this.emit('moneyChanged', this.amount);
};

リスナーを実装して動作確認

const cash = new Wallet();

cash.on('moneyChanged', (current) => {
  console.log(`残高: ${current} 円`);
});

cash.on('moneyChanged', (current) => {
  if (current < 0) console.warn('マイナス残高です!');
});

cash.once('moneyChanged', (current) => {
  if (current >= 10000) console.log('目標達成!');
});

cash.income(3000);
cash.income(8000);
cash.outgo(12000);

実行結果

残高: 3000 円
残高: 11000 円
目標達成!
残高: -1000 円
マイナス残高です!

このように EventEmitter を継承するだけで、独自クラスでも .on().emit() を使ってイベント駆動型の設計が可能になる。

タグ: Node.js EventEmitter javascript Observer Pattern Prototype Inheritance

6月15日 22:36 投稿