カスタムイベントまとめ


プリロード処理が完了したときにイベントを発行したいとか`EVENT.COMPLETE`
dom要素の高さが確定したときにイベントを発行したいとか`EVENT.HEIGHT_FIXED`
顔認識で対象を検出したときにイベントを発行したいとか`EVENT.DETECTED`
使い所の多いカスタムイベントのまとめ。
（イベント名は仮です）

## EventEmitter

cdnで読み込む（node.jsなら不要）
https://cdnjs.com/libraries/EventEmitter

デモ：http://codepen.io/mo4_9/pen/ZOVEWW

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/EventEmitter/5.1.0/EventEmitter.min.js"></script>
```


```javascript:EventEmitter
var eventEmitter = new EventEmitter();
// 必ずしもEVENTオブジェクトをつくる必要はないが、
// カスタムイベントであることがわかりやすいのでオススメ
var EVENT = {
  DETECTED: 'detected',
  COMPLETE: 'complete'
};

// Listen for the event.
eventEmitter.on(EVENT.DETECTED, () => {
  console.log('DETECTED 発火！');
});
eventEmitter.on(EVENT.COMPLETE, () => {
  console.log('COMPLETE 発火！');
});

// Dispatch the event.
setTimeout(() => {
    eventEmitter.emit(EVENT.DETECTED);
}, 1000);
setTimeout(() => {
    eventEmitter.emit(EVENT.COMPLETE);
}, 3000);
```

応用例：[【祝！リニューアル】カヤック 新コーポレートサイト、5種類テーマ切り替えの裏側！【フロントエンド芸】](http://tech.kayac.com/archive/kayac_site_renewal.html)

こちらの応用例を元に書いた記事
http://qiita.com/mo4_9/items/4c12ad835b329ddc663c

## JavaScript | dispatchEvent


```javascript:DOMに紐づくEventDispatcher
var event = new Event('build');

// Listen for the event.
elem.addEventListener('build', function (e) { ... }, false);

// Dispatch the event.
elem.dispatchEvent(event);
```
以下の記事のようにクラス内部でイベントを発行して、外部に持ち出してあげるのが良い使い方。依存関係をなくせるのが利点。
[javascriptでEventDispatcherを使うときのメモ](http://qiita.com/w650/items/70de5af057f558b5aa6a)

> 参考
[Creating and triggering events](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events)


## jQuery | trigger

```javascript:DOMに紐付いていないEventDispatcher
const $dispatcher = $({});

// Listen
$dispatcher.on('complete', e => { ... });

// Dispatch
setTimeout( () => {
  $dispatcher.trigger('complete');
}, 1000);
```
使用例：プリロード
http://codepen.io/mo4_9/pen/VjqRqd

使用例：カウンターとポップアップ
http://codepen.io/mo4_9/pen/RREGwO

カウンターが7の倍数の時にポップアップを表示する。
カウンターとポップアップの機能は独立させたいので、別々にクラスをつくる。カウンターにDOMイベントを登録して、その中でポップアップのメソッドを実行する。

> 参考
[jQuery初心者のためのJavaScript設計トレーニング 第1回 機能や役割に着目したコード整理](https://app.codegrid.net/entry/js-training-for-beginners-1#toc-1)


## jQuery.callbacks()

DOMに紐付かないのに無駄にカスタムイベントを使ったり、Ajax通信でdone()やresolve()しか呼び出さないのに無駄にDeferredを使うくらいなら、`jQuery.callbacks()`を使ったほうがいいという認識が多い。
単純に任意のタイミングで関数を実行したいときに使える。オプション指定で実行制御も可能。

```javascript
function hoge () {
  console.log("hoge");
}
function piyo () {
  console.log("piyo");
}

// コールバックオブジェクトを作成
const callbacks = $.Callbacks();
// コールバックに関数を登録
callbacks.add(hoge);
callbacks.add(piyo);
// 実行
callbacks.fire();
```

```javascript:console.log
'hoge'
'piyo'
```

> 参考
https://api.jquery.com/jQuery.Callbacks/
http://www.jquerystudy.info/reference/callbacks/callbacks.html

## Pub/Sub

デザパタ（オブザーバ）の一種Pub/Sub（パブリッシュ／サブスクライブ）
カスタムイベントの応用形みたいなニュアンス
上記の`jQuery.callbacks()`もPub/Subだし、大きく分けるとカスタムイベントもPub/Subに含まれるという考えもあるが、まあ実務で支障なく使えればいい。
[フロントエンドjavascriptのpubsubパターンとカスタムイベントの違い・使い分け](http://ja.stackoverflow.com/questions/7037/%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89javascript%E3%81%AEpubsub%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%A8%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E9%81%95%E3%81%84-%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91)

[pubsub-js](https://www.npmjs.com/package/pubsub-js)のサンプル

```javascript:Topic1.js
import $ from 'jquery';
import PubSub from 'pubsub-js';

export default class Topic1 {

  constructor(opts = {}) {
	this.TOPIC_NAME = 'TOPIC1';
	this.init();
  }
  
  init() {
	const $btn1 = $('.btn').eq(0);
	$btn1.on('click', () => {
	  // 発行
	  PubSub.publish(`btnClick.${this.TOPIC_NAME}`, `hello world, ${this.TOPIC_NAME}`);
	})
  }
  
}
```

```javascript:script.js
import PubSub from 'pubsub-js';
import Topic1 from './Topic1';

// 購読
PubSub.subscribe( 'btnClick.TOPIC1', mySubscriber );
function mySubscriber ( msg, data ) {
  console.log(`msg : ${msg}`, `data : ${data}`);
  // msg : btnClick.TOPIC1 data : hello world, TOPIC1
}
```

`pubsub-js`をimportしておけば、別ファイルや別クラスの内部でもカスタムイベントを発行・購読できる。インスタンスを生成して`topic1.btnClick.TOPIC1`みたいにしなくてよいので、慣れれば便利。


> 参考
[javascriptで発行/購読パターンを使ってモジュールの関係を疎結合に保つ](http://qiita.com/kanohisa/items/b7666133d46472f75690)
[【JSでデザインパターン】オブザーバ編](http://qiita.com/kenju/items/3cee3a1907fbd71b7b76)

## 結論

個人的にはEventEmitterとjQueryのtriggerが使いやすくて好き。

自作もできるけど、ややこしくなるのでやめたほうがいい
[シンプルな EventDispatcher つくりました](http://kimizuka.hatenablog.com/entry/2014/07/06/000000)