2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EventEmitterの設計戦略:JavaScriptにおける独自イベント駆動構造と責務分離のための通信モデル

Posted at

概要

JavaScript(特にNode.js)において、EventEmitterカスタムイベントを中心にした通信インターフェースとして利用される。
これにより、モジュールやレイヤー間の疎結合な双方向通信が可能となり、UIコンポーネントの再利用性、非同期処理の柔軟性、責務の明確な分離を実現できる。

本稿では以下を扱う:

  • EventEmitter の基本APIと構造
  • イベント購読・発火・解除の流れ
  • クラスベースでのカスタム実装
  • DOMのイベントと明確に分けた抽象化の意義
  • アーキテクチャ設計上の使い所と注意点

Node.jsのEventEmitter基本構文

const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.on('login', user => {
  console.log(`${user} logged in`);
});

emitter.emit('login', 'toto'); // "toto logged in"
  • on(event, listener) → イベント購読
  • emit(event, data) → イベント発火
  • off(event, listener) → イベント解除(Node 10以降)

onceで一度きりのリスナー設計

emitter.once('init', () => {
  console.log('Initialized');
});

→ ✅ 初回のみ有効 → 初期化処理、初回ロード検出などに有効


リスナーの解除

function handler() {
  console.log('Logout event');
}

emitter.on('logout', handler);
emitter.off('logout', handler);

→ ✅ 明示的な解除でメモリリーク防止


イベントを内包するクラス構造(カスタムラッパー)

class AuthService extends EventEmitter {
  login(user) {
    // ログイン処理...
    this.emit('login', user);
  }

  logout() {
    this.emit('logout');
  }
}

const auth = new AuthService();
auth.on('login', u => console.log(`${u} is online`));
auth.login('toto');

→ ✅ イベントの設計単位をクラスの責務に内包


DOMイベントとの明確な違い

項目 EventEmitter DOMイベント
発火元 任意のオブジェクト DOMノード
イベント名 自由な文字列 固定されたDOMイベント(click等)
バブリング/キャプチャ ❌ なし ✅ あり
ライフサイクル制御 ✅ メソッドで明示的に管理 ❌ 暗黙的

イベント駆動設計の責務分離パターン

[UI Layer] ── on('submit') → [FormService] ── emit('submitted') → [Logger/Analytics]
  • ✅ 複数のリスナーが独立に反応
  • ✅ UI・処理・ログなどの責務を「イベント」で中継可能
  • ✅ テスト容易・柔軟な構成変更が可能

イベントバス(event bus)としての活用

const EventBus = new EventEmitter();

// グローバル通信ハブとしてUI間を接続
EventBus.on('notify', msg => alert(msg));
EventBus.emit('notify', '登録に成功しました');

→ ✅ シンプルなグローバルメッセージング構造


よくある注意点

❌ メモリリーク(過剰なリスナー)

emitter.setMaxListeners(10); // 超えると警告

→ ✅ removeListener, off, once で制御必須


❌ 同一イベント名の曖昧さ

→ ✅ イベント名は明示的にドメイン命名:user:login, system:shutdown など


設計判断フロー

① オブジェクト間を疎結合でつなぎたい? → EventEmitter

② 特定の処理後に任意数のリスナーを通知したい? → emitパターン

③ モジュールごとにイベント定義したい? → クラス継承 + EventEmitter

④ グローバル通信が欲しい? → EventBus設計

⑤ イベント数が多い? → イベント名を明示的に命名(名前空間風)

結語

EventEmitter は「状態に反応するという設計思想」を、構文として提供する。
それは単なるAPIではなく、「責務の通知可能な抽象化」である。

  • 情報の流れを疎結合に制御し、
  • 処理の分岐を設計的に明示し、
  • 再利用可能でテストしやすい構造を作る

関数を呼ぶのではなく、反応させる。
それがイベント駆動設計の本質であり、EventEmitter の力である。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?