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() を使ってイベント駆動型の設計が可能になる。