タスクが完了したら、コールバックを渡すか、プログラム内の他の関数から関数をトリガーして、物事を起こしています。何かが終了したら、関数を直接トリガーします。
var ground = 'clean';
function shovelSnow(){
console.log("Cleaning Snow");
ground = 'clean';
}
function makeItSnow(){
console.log("It's snowing");
ground = 'snowy';
shovelSnow();
}
しかし、プログラミングのさまざまな戦略について読んだことがあり、強力であると理解していますが、まだ実践していませんが、イベントベースです(私が読んだ方法は、呼び出されたと思います"pub-sub"):
var ground = 'clean';
function shovelSnow(){
console.log("Cleaning Snow");
ground = 'clean';
}
function makeItSnow(){
console.log("It's snowing");
ground = 'snowy';
$(document).trigger('snow');
}
$(document).bind('snow', shovelSnow);
イベントベースのプログラミングの客観的な長所と短所を理解したいのですが、他の関数内からすべての関数を呼び出すだけです。イベントベースのプログラミングはどのプログラミング状況で使用する意味がありますか?
イベントは、最近の過去からの発生を説明する通知です。
イベント駆動型システムの一般的な実装では、イベントディスパッチャーおよびハンドラー関数(またはサブスクライバー)を利用します。ディスパッチャーは、ハンドラーをイベント(jQueryのbind
)にワイヤリングするAPIと、イベントをサブスクライバーにパブリッシュするメソッド(jQueryのtrigger
)を提供します。 IOまたはUIイベントについて話している場合、通常はイベントループもあり、マウスクリックなどの新しいイベントを検出してディスパッチャに渡します。 JSランドでは、ディスパッチャとイベントループはブラウザによって提供されます。
ユーザーと直接対話するコードの場合-キープレスとクリックに応答する-イベント駆動型プログラミング(または 機能的反応型プログラミング などのそのバリエーション)はほとんど避けられません。プログラマーは、ユーザーがいつどこをクリックするかわからないので、イベントループでユーザーのアクションを検出してコードに通知するのは、GUIフレームワークまたはブラウザーにかかっています。このタイプのインフラストラクチャは、ネットワーキングアプリケーションでも使用されます(NodeJSを参照)。
イベントを発生させるあなたの例あなたのコードで関数を直接呼び出すのではなく、いくつかの興味深いトレードオフがあります。これについては以下で説明します。主な違いは、イベントのパブリッシャー(makeItSnow
)が呼び出しの受信者を指定しないことです。それは別の場所に接続されています(例ではbind
への呼び出しで)。これはfire-and-forgetと呼ばれます:makeItSnow
は雪が降っていることを世界に知らせますが、誰が聞いているか、次に何が起こるか、いつ起こるかは関係ありません-単にメッセージをブロードキャストし、その手からほこりを払います。
したがって、イベント駆動型のアプローチは、メッセージの送信者を受信者から切り離します。これにより得られる利点の1つは、特定のイベントに複数のハンドラーがある場合があることです。既存のgritRoads
ハンドラーに影響を与えることなく、shovelSnow
関数をsnowイベントにバインドできます。アプリケーションの接続方法に柔軟性があります。動作をオフにするには、コードを探し回って動作のすべてのインスタンスを見つけるのではなく、bind
呼び出しを削除するだけです。
イベント駆動型プログラミングのもう1つの利点は、横断的な関心事をどこかに置くことができるということです。イベントディスパッチャーは Mediator の役割を果たし、一部のライブラリ( Brighter など)はパイプラインを利用するため、ロギングや品質などの一般的な要件を簡単にプラグインできます。サービスの。
完全な開示:Brighterは、私が働いているHuddleで開発されています。
イベントの送信者と受信者を切り離すことの3番目の利点は、イベントを処理するときにwhenに柔軟性を与えることです。独自のスレッドでイベントの各タイプを処理できます(イベントディスパッチャーがサポートしている場合)。または、発生したイベントを RabbitMQ などのメッセージブローカーに配置し、非同期プロセスまたはプロセスで処理することもできます。一晩でそれらをまとめて。イベントの受信者は、別のプロセスまたは別のマシン上にある可能性があります。これを行うためにイベントを発生させるコードを変更する必要はありません!これが「マイクロサービス」アーキテクチャの背後にある大きなアイデアです。自律サービスは、アプリケーションのバックボーンとしてメッセージングミドルウェアを使用して、イベントを使用して通信します。
イベント駆動型のやや異なる例については、ドメイン駆動型の設計を参照してください。ここでは、集計を個別に保つために domain events が使用されています。たとえば、購入履歴に基づいて製品を推奨するオンラインストアを考えてみます。 Customer
は、ShoppingCart
の支払い時に購入履歴を更新する必要があります。 ShoppingCart
集合体は、Customer
イベントを発生させることによってCheckoutCompleted
に通知する場合があります。 Customer
は、イベントに応答して別のトランザクションで更新されます。
このイベント駆動型モデルの主な欠点は間接性です。 IDEを使用してナビゲートするだけではできないため、イベントを処理するコードを見つけるのが難しくなりました。イベントが構成のどこにバインドされているかを把握し、すべてのハンドラーが見つかったことを期待する必要があります。いつでも頭の中に保管しておくべきものがもっとあります。ここではコードスタイルの規則が役立ちます(たとえば、bind
へのすべての呼び出しを1つのファイルに入れる)。健全性のために、1つのイベントディスパッチャのみを使用し、一貫して使用することが重要です。
別の欠点は、イベントのリファクタリングが難しいことです。イベントのフォーマットを変更する必要がある場合は、すべてのレシーバーも変更する必要があります。これは、イベントのサブスクライバーが別のマシン上にある場合に悪化します。これは、ソフトウェアリリースを同期する必要があるためです。
特定の状況では、パフォーマンスが問題になる場合があります。メッセージを処理するとき、ディスパッチャは次のことを行う必要があります。
これは確かに通常の関数呼び出しよりも遅く、スタックに新しいフレームをプッシュするだけです。ただし、イベント駆動型アーキテクチャが提供する柔軟性により、遅いコードの分離と最適化がはるかに簡単になります。非同期プロセッサに作業を送信する機能があると、ハードワークがバックグラウンドで処理されている間、要求をすぐに処理できるため、ここでは大きなメリットがあります。いずれにせよ、DBを操作したり、画面上で描画したりしている場合、IOのコストは、メッセージの処理コストを完全に圧倒します。これは、時期尚早な最適化を回避するケースです。
要約すると、イベントは疎結合ソフトウェアを構築するための優れた方法ですが、コストがかからないわけではありません。たとえば、アプリケーションのevery関数呼び出しをイベントに置き換えるのは誤りです。イベントを使用して、意味のある建築分割を行います。
イベントベースのプログラミングは、プログラムが実行する一連のイベントを制御しない場合に使用されます。代わりに、プログラムフローは、ユーザー(GUIなど)、別のシステム(クライアント/サーバーなど)、または別のプロセス(RPCなど)などの外部プロセスによって指示されます。
たとえば、バッチ処理スクリプトは、実行する必要があることを知っているので、実行するだけです。 notイベントベースです。
ワープロがそこに座って、ユーザーが入力を開始するのを待ちます。キープレスは、内部ドキュメントバッファを更新する機能をトリガーするイベントです。プログラムは入力したい内容を認識できないため、イベント駆動型でなければなりません。
ほとんどのGUIプログラムは、ユーザーインタラクションを中心に構築されているため、イベント駆動型です。ただし、イベントベースのプログラムはGUIに限定されず、GUIはほとんどの人にとって最も身近な例です。 Webサーバーは、クライアントの接続を待機し、同様のイディオムに従います。コンピュータ上のバックグラウンドプロセスもイベントに応答する場合があります。たとえば、オンデマンドウイルススキャナーは、新しく作成または更新されたファイルに関するイベントをOSから受信し、そのファイルでウイルスをスキャンします。
イベントベースのアプリケーションでは、イベントリスナーの概念により、さらに多くの機能を記述できます疎結合アプリケーション。
たとえば、サードパーティのモジュールまたはプラグインは、データベースからレコードを削除してからreceordDeleted
イベントをトリガーし、残りをイベントリスナーに任せて作業を任せることができます。トリガーモジュールは、この特定のイベントを誰がリッスンしているか、次に何が発生するかさえわからなくても、すべてが正常に機能します。
私が追加したかった単純な類推は私を助けました:
アプリケーションのコンポーネント(またはオブジェクト)を、Facebookの友達の大きなグループと考えてください。
友だちの1人が何かを伝えたい場合は、直接電話をかけるか、Facebookのウォールに投稿できます。 Facebookに投稿すると、anyonecouldはそれを見て反応しますが、多くの人はそうしませんt。 「私たちは赤ん坊を産んでいる!」のように、人々がそれに反応する必要がある可能性が高いことは時々重要です。または「Dandkin 'Clamバーでバンドがサプライズコンサートを行っています!」。最後のケースでは、他の友達も、特にそのバンドに興味がある場合は、それに反応する必要があるでしょう。
あなたの友人があなたと彼らの間で秘密を守りたいと思っているなら、彼らはおそらくそれを彼らのFacebookの壁に投稿しないでしょう、彼らはあなたに直接電話してあなたに話します。好きな女の子にレストランでデートしたいと言ったシナリオを想像してください。彼女に直接電話して尋ねるのではなく、Facebookのウォールに投稿して、すべての友達に見てもらいます。これは機能しますが、嫉妬深い元がいれば、彼女はそれを見て、レストランに現れて1日を台無しにするかもしれません。
何かを実装するためのイベントリスナーを組み込むかどうかを決定するときは、この類似性を考慮してください。このコンポーネントは、誰でも見ることができるようにビジネスを公開する必要がありますか?または、誰かに直接電話をかける必要がありますか?物事はかなり簡単に乱雑になるので注意してください。
この次の例えは、ドクターズレセプションデスクで待機線と平行に線を引くことで、イベント駆動型I/Oプログラミングを理解するのに役立ちます。
I/Oのブロックは、キューに立っている場合、受付係が目の前の人にフォームに記入するように依頼し、彼女が完了するまで待機するようなものです。男が彼のフォームを完了するまであなたのターンを待たなければなりません、これはブロックしています。
一人の男が記入に3分かかる場合、10番目の男は30分まで待たなければなりません。この10人の待機時間を減らすための解決策は、受付係の数を増やすことです。これはコストがかかります。これは、従来のWebサーバーで発生することです。ユーザー情報を要求した場合、他のユーザーによる後続の要求は、データベースからのフェッチである現在の操作が完了するまで待機する必要があります。これにより、10番目の要求の「応答時間」が増加し、n番目のユーザーの場合は指数関数的に増加します。この従来のWebサーバーを回避するために、1つの要求ごとにスレッド(受付数の増加に相当)を作成します。つまり、基本的に、要求ごとにサーバーのコピーを作成します。これは、すべての要求でオペレーティングシステムが必要になるため、CPU消費のコストがかかります。糸。アプリをスケールアップするには、アプリに大量の計算能力を投入する必要があります。
イベントドリブン:キューの「応答時間」を拡大するもう1つの方法は、イベントドリブンアプローチを採用することです。フォームに記入し、完了時に戻ってきてください。したがって、受付係は常に要求を受け取ることができます。これは、JavaScriptが誕生して以来、まさにJavaScriptが行っていることです。ブラウザでは、JavaScriptはユーザーのクリックイベント、スクロール、スワイプ、またはデータベースのフェッチなどに応答します。これはjavascriptで本質的に可能です。javascriptは関数をファーストクラスオブジェクトとして扱い、それらをパラメーターとして他の関数(コールバックと呼ばれる)に渡すことができ、特定のタスクの完了時に呼び出すことができるためです。これは正確にnode.jsがサーバー上で行うことです。イベントドリブンプログラミングとブロックI/Oの詳細については、ノードのコンテキスト here