ブラウザ用の EventEmitter
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 2
◆ EventTarget を使う
◆ 長いメソッド名や Event インスタンス作成を内部で行うサブクラスを作るとちょっと便利に
◆ 長いメソッド名や Event インスタンス作成を内部で行うサブクラスを作るとちょっと便利に
ブラウザで複数箇所に複数回通知をしたいときは Promise よりも Event の仕組みが向いています
EventEmitter がブラウザにもあるといいのですが ないのでよくシンプルなものを作ってます
もっと高機能にもできますが 実際必要なものってリスナのつけ外しと呼び出しくらいで リスナ全削除やワイルドカードや once などはあっても使うシーンがかなり稀なので書く手間を考えるとこれで十分です
それでも毎回書くのってやっぱり面倒です
ブラウザには EventEmitter はなくても Event の仕組みはあります
window や document や各 HTMLElement など addEventListener を行えるものは EventTarget を継承しています
これが Event を扱えるものなので直接これのインスタンスを作れば EventEmitter に相当するものになります
このままだと長いのでもう少し短く書けるようにします
いい感じですね
リスナ関数が受け取るものは Node.js の EventEmitter と同じように emit で渡した引数そのままでもよかったのですが Event オブジェクトのほうがブラウザ的に慣れてますし type や timeStamp プロパティもあるしということでそのままにしました
これとか これとか
ES5 で書かれた昔のものしか見当たらなかったので書いてみたのですが ほぼ同じのが Short のほうにあることにあとから気づきました
なぜか Short の方だとググっても出ないんですよね
なのでこっちにもほぼ同じですが書いておくことにしました
EventEmitter がブラウザにもあるといいのですが ないのでよくシンプルなものを作ってます
const ee = new class {
fns = {}
on(type, fn) {
if (this.fns[type]) {
this.fns[type].add(fn)
} else {
this.fns[type] = new Set([fn])
}
}
off(type, fn) {
this.fns[type]?.delete(fn)
}
emit(type, ...args) {
for (const fn of this.fns[type] || []) fn(...args)
}
}
もっと高機能にもできますが 実際必要なものってリスナのつけ外しと呼び出しくらいで リスナ全削除やワイルドカードや once などはあっても使うシーンがかなり稀なので書く手間を考えるとこれで十分です
それでも毎回書くのってやっぱり面倒です
ブラウザには EventEmitter はなくても Event の仕組みはあります
window や document や各 HTMLElement など addEventListener を行えるものは EventTarget を継承しています
これが Event を扱えるものなので直接これのインスタンスを作れば EventEmitter に相当するものになります
const et = new EventTarget()
et.addEventListener("foo", eve => { console.log(eve) })
et.addEventListener("bar", eve => { console.log(eve) })
et.dispatchEvent(new Event("foo"))
// Event {isTrusted: false, type: "foo", ... }
et.dispatchEvent(new Event("bar"))
// Event {isTrusted: false, type: "bar", ... }
このままだと長いのでもう少し短く書けるようにします
class EE extends EventTarget {
on(...a) { this.addEventListener(...a) }
off(...a) { this.removeEventListener(...a) }
emit(type, ...args) { this.dispatchEvent(new CustomEvent(type, { detail: args })) }
}
const ee = new EE()
ee.on("foo", ({ type, detail }) => { console.log(type, detail) })
ee.on("bar", ({ type, detail }) => { console.log(type, detail) })
ee.emit("foo", 1, 2, 3)
// foo [1, 2, 3]
ee.emit("bar", 10, 20, 30)
// bar [10, 20, 30]
いい感じですね
リスナ関数が受け取るものは Node.js の EventEmitter と同じように emit で渡した引数そのままでもよかったのですが Event オブジェクトのほうがブラウザ的に慣れてますし type や timeStamp プロパティもあるしということでそのままにしました
Short で書いてた
今回の内容ですが 以前書いた気がするなぁと思いつつググってもこれとか これとか
ES5 で書かれた昔のものしか見当たらなかったので書いてみたのですが ほぼ同じのが Short のほうにあることにあとから気づきました
なぜか Short の方だとググっても出ないんですよね
なのでこっちにもほぼ同じですが書いておくことにしました