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?

JavaScriptにおけるイベント設計戦略:カスタムイベントとコールバックの使い分け

Posted at

概要

JavaScriptにおいて、ユーザーアクションや非同期処理の完了通知には イベントコールバック が使われる。
どちらも「通知」の手段だが、設計の観点から見ると結合度・柔軟性・スケーラビリティに大きな違いがある。

本稿では、コールバックとカスタムイベントの使い分け、イベントドリブン設計の指針、疎結合化のためのイベントアーキテクチャ戦略を解説する。


1. コールバックの基本と責務

function fetchData(callback) {
  setTimeout(() => {
    const result = { message: 'done' };
    callback(result);
  }, 1000);
}

fetchData((res) => {
  console.log('Result:', res.message);
});
  • ✅ 呼び出し元が「何をすべきか」を直接渡す
  • 高凝集・明示的な1対1の通信に向いている
  • ❌ コールバック地獄、拡張性の乏しさ、汎用化困難

2. カスタムイベントの基本と拡張性

const event = new CustomEvent('user:created', {
  detail: { name: 'Taro' }
});
document.dispatchEvent(event);

document.addEventListener('user:created', (e) => {
  console.log('Created user:', e.detail.name);
});
  • ✅ イベント発火元とリスナーが疎結合 → 柔軟な通知設計
  • ✅ イベント名・detailにより拡張可能
  • 1対多通信将来的な変更に強い

3. 使い分け戦略:明示 vs 汎用

条件 推奨形式
単一箇所でのみ使用される通知 コールバック
汎用イベント(ログイン・エラー通知など) カスタムイベント
外部ライブラリ連携 コールバック
UI構成間通信(モジュール間通信) カスタムイベント

4. カスタムイベントの拡張設計

class EventBus extends EventTarget {
  emit(name, detail) {
    this.dispatchEvent(new CustomEvent(name, { detail }));
  }

  on(name, handler) {
    this.addEventListener(name, handler);
  }

  off(name, handler) {
    this.removeEventListener(name, handler);
  }
}

const bus = new EventBus();

bus.on('login', (e) => {
  console.log('User login:', e.detail.username);
});

bus.emit('login', { username: 'admin' });
  • ✅ 独自の イベントバス(PubSub) 実装で再利用性とテスト性を両立
  • ✅ アプリケーション全体に 分離された通知ライン を持てる

5. 結合度と拡張性の設計基準

観点 コールバック カスタムイベント
結合度 高(呼び出し側と処理が密結合) 低(発火元と受信先が分離)
拡張性 低(1対1構造) 高(1対多、将来の追加に強い)
テスト性 高(関数単位) 中(リスナ登録のテストが必要)
保守性 低(処理の移植が難しい) 高(通知が宣言的)

設計判断フロー

① 通知の対象は一箇所か? → コールバックでシンプルに

② 複数のリスナーに通知したいか? → カスタムイベント

③ モジュール間を疎結合にしたいか? → イベントバスを導入

④ イベントの種類は将来的に増えるか? → カスタムイベントを前提に設計

⑤ イベントにペイロードを持たせたいか? → detail を活用して設計する

よくあるミスと対策

❌ コールバックを多重にネストし、制御不能なコールバック地獄に

→ ✅ Promise / async に置き換える or 責務ごとに分離


❌ カスタムイベントを乱用し、どこで何が発火しているかわからない

→ ✅ EventBusを設け、名前・スコープ・責務を明示


❌ リスナーを登録したまま削除忘れでメモリリーク

→ ✅ off を徹底 or once フラグで自動解除する仕組みを導入


結語

イベント設計は、単なる「通知のしかた」ではない。
それは**“情報伝達の責任と結合度を設計し、モジュール間の流れと柔軟性を統御するための戦略”**である。

  • コールバック:シンプル・直接的。責務が明確
  • カスタムイベント:柔軟・宣言的。責務を分離し、拡張に強い
  • 設計段階で「今後の変化」にどこまで耐えるかを見据えて選択する

JavaScriptにおけるイベント設計とは、
“モジュール間の通信を設計構造として表現し、責務分離と拡張性を最大化する技術戦略である。”

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?