イベントは、最近の過去から発生したことを記述した通知です。
イベント駆動型システムの典型的な実装では、イベントディスパッチャーとハンドラー関数(またはサブスクライバー)を利用します。ディスパッチャーは、ハンドラーをイベント(jQueryのbind
)に接続するAPI と、サブスクライバーにイベントを公開するメソッド(jQueryの)を提供しますtrigger
。IOまたはUIイベントについて説明している場合、通常はイベントループもあります。これは、マウスクリックなどの新しいイベントを検出し、それらをディスパッチャーに渡します。JSランドでは、ディスパッチャーとイベントループはブラウザーによって提供されます。
ユーザーと直接やり取りするコード-キー押下とクリックへの応答-では、イベント駆動型プログラミング(または関数型リアクティブプログラミングなどのそのバリエーション)はほとんど避けられません。プログラマーは、いつ、どこでユーザーがクリックするのかわからないので、イベントループでユーザーのアクションを検出し、コードに通知するのはGUIフレームワークまたはブラウザーです。このタイプのインフラストラクチャは、ネットワークアプリケーションでも使用されます(NodeJSを参照)。
関数を直接呼び出すのではなく、コードでイベントを発生させる例には、さらに興味深いトレードオフがあります。これについては、以下で説明します。主な違いは、イベントの発行者(makeItSnow
)が呼び出しの受信者を指定しないことです。それは他の場所で結ばれています(bind
あなたの例の呼び出しで)。これが呼び出されファイア・アンド・フォーゲット:makeItSnow
雪が降っていますことを世界に発表しましたが、聞いています誰が気にしない、次に何が起こるか、それが起こるとき-それは単にメッセージをブロードキャストし、その手をオフダスト。
そのため、イベント駆動型のアプローチでは、メッセージの送信者と受信者を分離します。これにより得られる利点の1つは、特定のイベントに複数のハンドラーがあることです。gritRoads
既存のshovelSnow
ハンドラーに影響を与えることなく、関数をsnowイベントにバインドできます。アプリケーションの接続方法に柔軟性があります。動作をオフにするにはbind
、コードを探して動作のすべてのインスタンスを見つけるのではなく、呼び出しを削除するだけです。
イベント駆動型プログラミングのもう1つの利点は、横断的な懸念をどこかに置くことができることです。イベントディスパッチャはMediatorの役割を果たし、一部のライブラリ(Brighterなど)はパイプラインを使用するため、ロギングやサービス品質などの一般的な要件を簡単にプラグインできます。
完全な開示:Brighterは、私が働いているハドルで開発されています。
イベントの送信者を受信者から切り離すことの3番目の利点は、イベントを処理する際の柔軟性が得られることです。各タイプのイベントを独自のスレッドで処理できます(イベントディスパッチャーがサポートしている場合)。または、RabbitMQなどのメッセージブローカーに発生したイベントを配置し、非同期プロセスで処理したり、一晩で一括処理したりすることもできます。イベントの受信者は、別のプロセスまたは別のマシン上にある可能性があります。これを行うためにイベントを発生させるコードを変更する必要はありません!これが「マイクロサービス」アーキテクチャの背後にある大きなアイデアです。自律サービスは、アプリケーションのバックボーンとしてメッセージングミドルウェアとイベントを使用して通信します。
イベントドリブンスタイルのかなり異なる例については、ドメインドリブンデザインを参照してください。ここでは、ドメインイベントを使用して集計を分離します。たとえば、購入履歴に基づいて製品を推奨するオンラインストアを考えてみましょう。の支払いCustomer
時に、購入履歴を更新する必要がありますShoppingCart
。ShoppingCart
集計は、通知可能性がCustomer
高くすることによりCheckoutCompleted
、イベントを。Customer
イベントに応答して別のトランザクションで更新になるだろう。
このイベント駆動型モデルの主な欠点は、間接指定です。IDEを使用してイベントにナビゲートすることができないため、イベントを処理するコードを見つけるのが難しくなりました。イベントが構成のどこにバインドされているかを把握し、すべてのハンドラーが見つかったことを期待する必要があります。いつでもあなたの頭の中に留めておくべきことがあります。ここでは、コードスタイルの規則が役立ちます(たとえば、すべての呼び出しをbind
1つのファイルに入れる)。正気のために、イベントディスパッチャを1つだけ使用し、一貫して使用することが重要です。
別の欠点は、イベントのリファクタリングが難しいことです。イベントの形式を変更する必要がある場合は、すべての受信者も変更する必要があります。これは、ソフトウェアリリースを同期する必要があるため、イベントのサブスクライバーが異なるマシン上にある場合に悪化します!
特定の状況では、パフォーマンスが問題になる場合があります。メッセージを処理するとき、ディスパッチャは次のことを行う必要があります。
- いくつかのデータ構造で正しいハンドラーを検索します。
- 各ハンドラーのメッセージ処理パイプラインを構築します。これには、大量のメモリ割り当てが含まれる場合があります。
- ハンドラーを動的に呼び出します(言語で必要な場合は、おそらくリフレクションを使用します)。
これは、スタックに新しいフレームをプッシュするだけの通常の関数呼び出しよりも確かに遅いです。ただし、イベント駆動型アーキテクチャが提供する柔軟性により、遅いコードの分離と最適化がはるかに容易になります。非同期プロセッサに作業を送信できることは、ハードワークがバックグラウンドで処理されている間、すぐにリクエストに応えることができるため、大きなメリットです。いずれにせよ、DBとやり取りしたり、画面上に物を描画したりすると、IOのコストがメッセージの処理コストを完全に圧倒します。これは、時期尚早な最適化を回避する場合です。
要約すると、イベントは疎結合ソフトウェアを構築するための優れた方法ですが、費用がないわけではありません。たとえば、アプリケーション内のすべての関数呼び出しをイベントに置き換えるのは間違いです。イベントを使用して、意味のあるアーキテクチャ分割を行います。
$(document).bind('snow', shovelShow)
。無名関数でラップする必要はありません。