コールバックを渡すか、プログラム内の他の関数から関数をトリガーして、タスクが完了したら処理を実行しています。何かが終了したら、関数を直接トリガーします:
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);
イベントの客観的な長所と短所を理解したいベースのプログラミングと、他の関数内からすべての関数を呼び出すだけの場合。イベントベースのプログラミングはどのプログラミング状況で使用するのが理にかなっていますか?
コメント
回答
イベント は、最近の過去の出来事を説明する通知です。
イベントドリブンシステムの一般的な実装では、イベントディスパッチャとハンドラ関数を使用します。 em>(またはサブスクライバー)。ディスパッチャは、ハンドラをイベントまでワイヤリングするためのAPI(jQueryのbind
)と、イベントをサブスクライバに公開するためのメソッド(trigger
)。「IOまたはUIイベントについて話しているときは、通常、イベントループもあります。これは、マウスクリックなどの新しいイベントを検出してディスパッチャに渡します。 JS-land、ディスパッチャ、およびイベントループはブラウザによって提供されます。
ユーザーと直接対話するコードの場合(キーの押下とクリックに応答する)、イベント駆動型プログラミング(または機能的なリアクティブプログラミング)はほぼ避けられません。プログラマーであるあなたは、ユーザーがいつどこでクリックするのかわからないため、GUIフレームワークに依存します。またはブラウザを使用して、イベントループでユーザーのアクションを検出し、コードに通知します。このタイプのインフラストラクチャは、ネットワーキングアプリケーション(NodeJSを参照)でも使用されます。
イベントを発生させる例よ関数を直接呼び出すのではなく、コードには、さらに興味深いトレードオフがいくつかあります。これについては、以下で説明します。主な違いは、イベントの発行者(makeItSnow
)が呼び出しの受信者を指定しないことです。これは他の場所に接続されています(例ではbind
の呼び出しで)。これはファイアアンドフォーゲットと呼ばれます:makeItSnow
は雪が降っていることを世界に発表しますが、誰が聞いているか、次に何が起こるか、いつ起こるかは関係ありません。メッセージをブロードキャストし、手からほこりを払います。
したがって、イベントドリブンアプローチは、メッセージの送信者を受信者から切り離します。これにより得られる利点の1つは、特定のイベントに複数のハンドラーが含まれる場合があることです。既存のshovelSnow
ハンドラーに影響を与えることなく、gritRoads
関数をsnowイベントにバインドできます。アプリケーションの接続方法に柔軟性があります。ビヘイビアーをオフにするには、コードを探し回ってビヘイビアーのすべてのインスタンスを見つけるのではなく、bind
呼び出しを削除するだけです。
のもう1つの利点イベントドリブンプログラミングは、横断的関心事をどこかに置くことができるということです。イベントディスパッチャはメディエーターの役割を果たし、一部のライブラリ(より明るいなど)はパイプライン。ロギングやサービス品質などの一般的な要件を簡単にプラグインできます。
完全な開示:Brighterは私が働いているHuddleで開発されています。
イベントの送信者を受信者から分離することの3番目の利点は、イベントを処理するときに 柔軟性が得られることです。各タイプのイベントを独自のスレッドで処理することも(イベントディスパッチャーがサポートしている場合)、発生したイベントを RabbitMQ などのメッセージブローカーに配置することもできます。それらを非同期プロセスで処理するか、一晩でまとめて処理します。イベントの受信者は、別のプロセスまたは別のマシンにある可能性があります。これを行うためにイベントを発生させるコードを変更する必要はありません!これは「マイクロサービス」アーキテクチャの背後にある大きなアイデアです。自律サービスはイベントを使用して通信し、メッセージングミドルウェアをアプリケーションのバックボーンとして使用します。
イベント駆動型スタイルのかなり異なる例については、ドメイン駆動設計を参照してください。ここで、 ドメインイベント は、集計を分離するために使用されます。たとえば、購入履歴に基づいて商品を推奨するオンラインストアについて考えてみます。 Customer
は、ShoppingCart
の支払い時に、購入履歴を更新する必要があります。 ShoppingCart
アグリゲートは、CheckoutCompleted
イベントを発生させることにより、Customer
に通知する場合があります。 Customer
は、イベントに応じて別のトランザクションで更新されます。
このイベント駆動型モデルの主な欠点は、間接参照です。 IDEを使用してイベントに移動することはできないため、イベントを処理するコードを見つけるのが難しくなりました。構成内のどこでイベントがバインドされているかを把握し、「すべてのハンドラーが見つかったことを期待する必要があります。一度に頭に入れておくべきことがもっとあります」。ここでは、コードスタイルの規則が役立ちます(たとえば、bind
へのすべての呼び出しを1つのファイルに入れます)。正気を保つために、「イベントディスパッチャを1つだけ使用し、それを一貫して使用することが重要です。
もう1つの欠点は、イベントのリファクタリングが難しいことです。イベントの形式を変更する必要がある場合は、すべてのレシーバーも変更する必要があります。これは、イベントのサブスクライバーが異なるマシンにいる場合に悪化します。これは、ソフトウェアリリースを同期する必要があるためです!
特定の状況では、パフォーマンスが問題になる場合があります。メッセージを処理するとき、ディスパッチャは次のことを行う必要があります。
- データ構造内の正しいハンドラを検索します。
- ハンドラごとにメッセージ処理パイプラインを構築します。これには、大量のメモリ割り当てが含まれる場合があります。
- ハンドラーを動的に呼び出します(言語で必要な場合はリフレクションを使用する可能性があります)。
これは通常の関数よりも確かに低速です。呼び出し。スタックに新しいフレームをプッシュするだけです。ただし、イベント駆動型アーキテクチャが提供する柔軟性により、スローコードの分離と最適化がはるかに簡単になります。非同期プロセッサに作業を送信する機能があることは、ハードワークがバックグラウンドで処理されている間に要求をすぐに処理できるため、ここでは大きなメリットです。いずれにせよ、「DBを操作したり、画面上に何かを描画したりする場合、IOのコストは、メッセージの処理のコストを完全に圧倒します。これは、時期尚早の最適化を回避する場合です。
要約すると、イベントは疎結合ソフトウェアを構築するための優れた方法ですが、コストがかからないわけではありません。たとえば、アプリケーションのすべての関数呼び出しをイベントに置き換えるのは間違いです。イベントを使用して、意味のあるアーキテクチャ上の区分を作成します。
コメント
- この回答は、5377 ‘と同じです。私が正解として選択した答え。 ‘さらに詳しく説明しているため、これをマークするように選択を変更しています。
- 速度はイベント駆動型コードの重大な欠点ですか?可能性があるようですが、’よくわかりません。
- @ raptortech97確かにそうです。特に高速である必要があるコードの場合、内部ループでイベントを送信することは避けたいと思うでしょう。幸いなことに、このような状況では、通常、何をする必要があるかが明確に定義されているため、’イベント(またはパブリッシュ/サブスクライブまたはオブザーバー)の柔軟性は必要ありません。異なる用語)。
- また、すべてがメッセージ(イベント)であるアクターモデルを中心に構築されたいくつかの言語(Erlangなど)があることにも注意してください。この場合、コンパイラはメッセージ/イベントを直接関数呼び出しとして実装するか、通信として実装するかを決定できます。
- “パフォーマンスの場合”シングルスレッドのパフォーマンスとスケーラビリティを区別する必要があると思います。メッセージ/イベントは、シングルスレッドのパフォーマンスでは悪化する可能性があり(ただし、追加コストなしで関数呼び出しに変換でき、悪化することはありません)、スケーラビリティに関しては、事実上すべての点で優れています’方法(たとえば、最新のマルチCPUおよび将来の”多くのCPU “システムでパフォーマンスが大幅に向上する可能性があります)。
回答
イベントベースのプログラミングは、プログラムが実行するイベントのシーケンスを制御しない場合に使用されます。代わりに、プログラムフローは、ユーザー(GUIなど)、別のシステム(クライアント/サーバーなど)、または別のプロセス(RPCなど)などの外部プロセスによって指示されます。
たとえば、バッチ処理スクリプトそれが何をする必要があるかを知っているので、それはただそれをします。 イベントベースではありません。
ワードプロセッサがそこにあり、ユーザーが入力を開始するのを待ちます。キー押下は、内部ドキュメントバッファを更新する機能をトリガーするイベントです。プログラムは入力したい内容を認識できないため、イベント駆動型である必要があります。
ほとんどのGUIプログラムは、ユーザーの操作を中心に構築されているため、イベント駆動型です。ただし、イベントベースのプログラムはGUIに限定されません。これは、ほとんどの人にとって最も身近な例です。 Webサーバーは、クライアントが接続して同様のイディオムに従うのを待ちます。コンピュータのバックグラウンドプロセスもイベントに応答する場合があります。たとえば、オンデマンドのウイルススキャナーは、新しく作成または更新されたファイルに関するイベントをOSから受信し、そのファイルをスキャンしてウイルスを検出する場合があります。
回答
イベントベースのアプリケーションでは、イベントリスナーの概念により、さらに多くの を記述できるようになります。疎結合 アプリケーション。
たとえば、サードパーティのモジュールまたはプラグインは、データベースからレコードを削除してから、receordDeleted
イベントを実行し、残りはイベントリスナーに任せて作業を行います。トリガーモジュールは、この特定のイベントを誰がリッスンしているか、次に何が発生するかさえ知らなくても、すべて正常に機能します。
回答
私が追加したかった簡単な例えが私を助けました:
アプリケーションのコンポーネント(またはオブジェクト)をFacebookの友達の大きなグループとして考えてください。
友達の1人があなたに何かを伝えたいときは、直接電話するか、Facebookのウォールに投稿することができます。 Facebookに投稿すると、誰でも それを見て反応することができますが、多くの人はそうしません。「私たちは赤ちゃんを産んでいます!」や「まあまあのバンドがDrunkinでサプライズコンサートをしている」など、人々がそれに反応する必要があるかもしれないことが重要なこともあります。 「クラムバー!」。最後のケースでは、特にそのバンドに興味がある場合は、残りの友達がそれに反応する必要があります。
友達があなたと友達の間に秘密を守りたい場合は、おそらくFacebookのウォールに投稿しないと、直接電話して教えてくれます。好きな女の子に、レストランでデートをしたいと言ったシナリオを想像してみてください。直接電話して尋ねる代わりに彼女、あなたはそれをFacebookの壁に投稿して、すべての友達に見せます。これは機能しますが、嫉妬深い元がいる場合、彼女はそれを見てレストランに現れ、あなたの一日を台無しにする可能性があります。
何かを実装するためにイベントリスナーを組み込むかどうかを決定するときは、このアナロジーについて考えてください。このコンポーネントは、誰もが見ることができるようにビジネスを公開する必要がありますか?それとも、誰かに直接電話する必要がありますか?注意してください。
回答
次の例は、あなたに役立つかもしれません。 u医師の受付で待機線と平行線を引くことにより、イベント駆動型I / Oプログラミングを理解します。
I / Oのブロックは、あなたが列に並んでいる場合、受付係があなたの前の男にフォームに記入するように頼み、彼が終了するまで待つようなものです。男がフォームを完成させるまで順番を待たなければなりません。これはブロックされています。
1人の男が記入するのに3分かかる場合、10人目の男は30分まで待たなければなりません。この10人目の待機時間を短縮するための解決策は、受付係の数を増やすことです。これはコストがかかります。これは従来のWebサーバーで発生することです。ユーザー情報を要求する場合、他のユーザーによる後続の要求は、データベースからフェッチする現在の操作が完了します。これにより、10番目のリクエストの「応答までの時間」が増加し、n番目のユーザーに対して指数関数的に増加します。この従来のWebサーバーを回避するために、すべてのリクエストに対してスレッド(受付係の数の増加に相当)が作成されます。つまり、基本的には、リクエストごとにサーバーのコピーを作成します。これは、リクエストごとにオペレーティングシステムスレッドが必要になるため、CPU消費のコストがかかります。アプリをスケールアップするには、アプリで大量の計算能力を投入する必要があります。 。
イベント駆動型:キューの「応答時間」をスケールアップするもう1つのアプローチは、イベント主導のアプローチを採用します。このアプローチでは、キュー内の男が引き渡されます。フォームに記入し、完了時に戻ってくるように求められます。したがって、受付係はいつでもリクエストを受け取ることができます。これは、javascriptが最初から行ってきたこととまったく同じです。ブラウザでは、javascriptはユーザーのクリックイベント、スクロール、スワイプ、データベースフェッチなどに応答します。これは、javascriptが関数をファーストクラスとして扱うため、本質的にjavascriptで可能です。オブジェクトとそれらは他の関数(コールバックと呼ばれる)にパラメーターとして渡すことができ、特定のタスクの完了時に呼び出すことができます。これはまさにnode.jsがサーバー上で行うことです。ノードここ
のコンテキストで、イベントドリブンプログラミングとI / Oのブロックに関する詳細情報を見つけることができます。
$(document).bind('snow', shovelShow)
を使用できます。匿名関数でラップする必要はありません。