電子冒険:エピソード40:ES 6プロキシでイベントバスAPI
26116 ワード
我々のコンポーネントは、イベントバスを介して通信し、それは我々が望むすべてを行い、実装は非常に簡単です.
一方、イベントコールは乱雑に見えます.例えば、ファイルをダブルクリックするためのハンドラです.
ES 6作成
ほとんどの人々は、それがES 6だけであるので、それのことを聞いたことがなく、そして、ES 6の残りとは異なり、これはBabelと交替することは不可能です.あなたがIEを支持しなければならなかった限り(バベル譲りを通して)、彼らを使う方法が全くありませんでした.
最近では、彼らは実際にVueのようなシーンの背後にあるいくつかのフレームワークによって使用されているが、彼らが作成されている厄介な方法のため、いくつかの人々が直接アプリでそれらを使用します.
また、彼らのパフォーマンスは驚くべきではありません、しかし、我々はちょうどここで良いAPIをしようとしています.
オリジナル
出発点はこちら
我々は欲しい
それから値を
これはどうにか有効なJavaScriptです.
これは
これの使い方?
実装は舞台裏で複雑でした、しかし、我々にはより良いAPIがあります:
より多くのプロキシ?
代わりに2層目のプロキシを使うことができました.
なぜ我々はこれが必要ですか?
明らかな質問は:なぜ我々はこれが必要ですか?
なぜ、我々はちょうど代わりにこれをすることができませんか
より大きな問題は
これを行うならば
結果
これまでの結果と同じです.
次のエピソードでは、おそらく聞いたことのないフレームワークを試してみましょう.
いつものように.all the code for the episode is here .
一方、イベントコールは乱雑に見えます.例えば、ファイルをダブルクリックするためのハンドラです.
function ondoubleclick() {
eventBus.emit("app", "activatePanel", panelId)
eventBus.emit(panelId, "focusOn", idx)
eventBus.emit(panelId, "activateItem")
}
なぜ、それはこのように見えませんか? function ondoubleclick() {
app.activatePanel(panelId)
panel.focusOn(idx)
panel.activateItem()
}
そうしましょう!Proxy
Rubyのような言語では、以下のように実装するのが非常に簡単ですmethod_missing
. JavaScriptは残念ながらそのようなことはありません.または少なくとも、それは使用しなかった.ES 6作成
Proxy
, これは特別な種類のオブジェクトですmethod_missing
と他のメタプログラミング.名前はかなり愚かです、それは良いAPIを作成するなどのプロキシのもの以外の多くの用途があるので.ほとんどの人々は、それがES 6だけであるので、それのことを聞いたことがなく、そして、ES 6の残りとは異なり、これはBabelと交替することは不可能です.あなたがIEを支持しなければならなかった限り(バベル譲りを通して)、彼らを使う方法が全くありませんでした.
最近では、彼らは実際にVueのようなシーンの背後にあるいくつかのフレームワークによって使用されているが、彼らが作成されている厄介な方法のため、いくつかの人々が直接アプリでそれらを使用します.
また、彼らのパフォーマンスは驚くべきではありません、しかし、我々はちょうどここで良いAPIをしようとしています.
オリジナル
EventBus
実装出発点はこちら
export default class EventBus {
constructor() {
this.callbacks = {}
}
handle(target, map) {
this.callbacks[target] = { ...(this.callbacks[target] || {}), ...map }
}
emit(target, event, ...details) {
let handlers = this.callbacks[target]
if (handlers) {
if (handlers[event]) {
handlers[event](...details)
} else if (handlers["*"]) {
handlers["*"](event, ...details)
}
}
}
}
Proxy
実装我々は欲しい
eventBus.target("app")
or eventBus.target(panelId)
何かを返すには、通常の関数呼び出しで使用できます.最初の部分は非常に簡単ですEventTarget
オブジェクト渡しbus
and target
引数として:export default class EventBus {
constructor() {
this.callbacks = {}
}
handle(target, map) {
this.callbacks[target] = { ...(this.callbacks[target] || {}), ...map }
}
emit(target, event, ...details) {
let handlers = this.callbacks[target]
if (handlers) {
if (handlers[event]) {
handlers[event](...details)
} else if (handlers["*"]) {
handlers["*"](event, ...details)
}
}
}
target(t) {
return new EventTarget(this, t)
}
}
今、我々は基本的に1つの大きな偽のオブジェクトを偽にする必要がありますmethod_missing
. どちらのメソッドを呼び出しても、そのイベントを呼び出す関数が返されます.class EventTarget {
constructor(bus, target) {
this.bus = bus
this.target = target
return new Proxy(this, {
get: (receiver, name) => {
return (...args) => {
bus.emit(target, name, ...args)
}
}
})
}
}
ここでアンパックをするのがたくさんある.最初我々セットthis.bus
and this.target
我々が厳密に話すとしても、彼らが閉鎖範囲にいるので、必要でありません.このようなプロキシを使ってコードをデバッグする必要があれば、コンソールでのデバッグ出力を読みやすくします.それから値を
constructor
. 値を返すconstructor
? あなたがちょうど他のどの言語にも慣れているならば、あなたは彼らのほとんどがそれを支持しないので、混乱しているかもしれません.しかし、クラスのコンストラクタは、クラスの新たなインスタンスよりも何か別のものを返すことができます.まあ、他のこともオブジェクトである限り、何らかの理由で文字列や数字を返すことはできません.これはどうにか有効なJavaScriptです.
class Cat {
constructor() {
return {cat: "No Cat For You!"}
}
meow() {
console.log("MEOW!")
}
}
let cat = new Cat() // what we returned here is not a Cat
cat.meow() // TypeError: cat.meow is not a function
我々はこの機能の1つの良いユースケースを持ってProxy
我々が作成するときEventTarget
. 私たちも、元のラップされていないオブジェクトを渡すthis
. しかし、本当に我々は何のためにそれを使用しないでください、我々がこれまでに使うすべては、このオブジェクトですget
.これは
eventBus.target("app").activatePanel(panelId)
以下に変換します.(new EventTarget(eventBus, "app")).activatePanel(panelId)
そうすると、(new Proxy(eventTarget, {get: ourGetFunction})).activatePanel(panelId)
以下のようになります.proxy.get("activatePanel")(panelId)
以下のようになります.((...args) => { eventBus.emit("app", name, ...args) })(panelId)
最後にeventBus.emit("app", name, panelId)
これの使い方?
実装は舞台裏で複雑でした、しかし、我々にはより良いAPIがあります:
let app = eventBus.target("app")
let panel = eventBus.target(panelId)
function onclick() {
app.activatePanel(panelId)
panel.focusOn(idx)
}
function onrightclick() {
app.activatePanel(panelId)
panel.focusOn(idx)
panel.flipSelected(idx)
}
function ondoubleclick() {
app.activatePanel(panelId)
panel.focusOn(idx)
panel.activateItem()
}
これは、 function onclick() {
eventBus.emit("app", "activatePanel", panelId)
eventBus.emit(panelId, "focusOn", idx)
}
function onrightclick() {
eventBus.emit("app", "activatePanel", panelId)
eventBus.emit(panelId, "focusOn", idx)
eventBus.emit(panelId, "flipSelected", idx)
}
function ondoubleclick() {
eventBus.emit("app", "activatePanel", panelId)
eventBus.emit(panelId, "focusOn", idx)
eventBus.emit(panelId, "activateItem")
}
より多くのプロキシ?
代わりに2層目のプロキシを使うことができました.
let app = eventBus.target("app")
let panel = eventBus.target(panelId)
それから、let app = eventBus.app
let panel = eventBus[panelId]
それをするために、私たちはProxy
からEventBus
コンストラクタget
呼び出しthis.target
. 読者のための運動としてこれを任せます.なぜ我々はこれが必要ですか?
明らかな質問は:なぜ我々はこれが必要ですか?
なぜ、我々はちょうど代わりにこれをすることができませんか
App.svelte
): eventBus.app = {switchPanel, activatePanel, quit, openPalette, closePalette}
eventBus.activePanel = eventBus[$activePanel]
そうすると、次のようにコードで使えます: let app = eventBus.app
let panel = eventBus[panelId]
let activePanel = eventBus.activePanel
app.switchPanel(panelId)
これには2つの問題があります.最初のコンポーネントはいくつかの順序で作成されます.したがって、1つのコンポーネントが初期化されたときにこれを実行したい場合、他のコンポーネントはまだそのイベントをeventBus.something
かもしれないundefined
その時点で.これはいくつかの遅延コールバックや反応性で回避することができますが、それはいくつかの他のボイラー板を保存するboilerplateを追加しています.より大きな問題は
let activePanel = eventBus.activePanel
. 我々がそうするならば、それはセットされますactivePanel
このコードが実行されたときにいずれかのパネルがアクティブになっていることを示します.それで、我々はそれを反応させる必要があるでしょう、しかし、何に関して?これを行うならば
$ activePanel = eventBus[$activePanelId]
次に、すべてのコンポーネントはアクティブパネルのIDでいくつかのストアにアクセスする必要があります.だから、さらに多くのboilerplate以上.EventBus
ベースの解決策は、イベントが実際にトリガされたときにターゲットを検索するだけで、そのような問題はありません.結果
これまでの結果と同じです.
次のエピソードでは、おそらく聞いたことのないフレームワークを試してみましょう.
いつものように.all the code for the episode is here .
Reference
この問題について(電子冒険:エピソード40:ES 6プロキシでイベントバスAPI), 我々は、より多くの情報をここで見つけました https://dev.to/taw/electron-adventures-episode-40-event-bus-api-with-es6-proxies-385pテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol