web-dev-qa-db-ja.com

カスタムブロードキャストイベントはJavaScript(またはjQuery)でどのように実装されますか?

特定のターゲットに送信するのではなく、「ブロードキャスト」できるカスタムイベントを実装したいと思います。そのようなイベントのリスナーとして自分自身を登録した要素のみがそれらを受け取ります。

私が考えていることは次のようになります。

まず、コードのさまざまな場所に、次の形式のステートメントがあります。

some_subscriber.on_signal( 'some_signal', some_handler );

「ブロードキャストイベント」の省略形としてsignalという用語を使用しています。上記の式では、some_subscriberは、ハンドラーを提供することにより、そのようなシグナルの1つのタイプ(「some_signal」と呼ばれる)のリスナーとして自身を登録します。

コードの他の場所には、次の形式のステートメントがあります

publisher.signal_types[ 'some_signal' ].broadcast( event_data );

このようなステートメントが実行されると、新しいイベントが生成され、「ブロードキャスト」が実行されます。これは、broadcastメソッドを呼び出すコードには、発行しているシグナルのリスナーに関する直接的な情報がないことを意味します。


私はこのアイデアのスケッチを this jsFiddle に実装しました。これは主に、上記の言葉で説明したことを説明するためです。1。 (確かに製品グレードではありません。私はそれができるとは特に確信していません。)

この実装の重要な要素は次のとおりです。まず、パブリッシャーオブジェクトは、サブスクライバーを追跡しません。これは、以下に示すようなパブリッシャーのファクトリメソッドの実装に見られます。

function make_publisher ( signal_types ) {

    // ...

    var _
    ,   signal = {}
    ,   ping = function ( type ) {
                   signal[ type ].broadcast( ... );
               }
    ;

    signal_types.forEach( function ( type ) {
                             signal[ type ] = $.register_signal_type( type );
                         } );

    return { signal_types: signal_types, ping: ping };
}

このパブリッシャーオブジェクトは、ブロードキャストするシグナルのタイプ(signal_types内)とpingメソッドの2つのアイテムのみを公開します。そのpingメソッドが呼び出されると、パブリッシャーはbroadcastingシグナルで応答します。

signal[ type ].broadcast( ... )

このブロードキャストの最終的な受信者は、このコードではどこにも表示されません。

次に、コードの他の場所で、サブスクライバーはこれらのブロードキャスト信号のリスナーとして自分自身を登録します。

    $( some_selector ).on_signal( signal_type, some_handler );

注:小さくて現実的な例を使用して、このスキームの理論的根拠を説明することは基本的に不可能です。この理由は、このスキームの長所は、パブリッシャーコードとサブスクライバーコード間の非常に疎な結合をサポートすることであり、これは小さな例では決して必要とされない機能です。それどころか、小さな例では、そのような疎結合を実装するコードは、常に不必要に複雑なものとして出くわします。したがって、この明らかな過度の複雑さはコンテキストのアーティファクトであることを覚えておくことが重要です。疎結合は、大規模なプロジェクトで非常に役立ちます。特に、パブリッシャー/サブスクライバータイプのパターンを介した疎結合は、MVCの重要な機能の1つです。


私の質問は:カスタムイベントの「ブロードキャスト」のこの効果を達成するためのより良い(または少なくともより標準的な)方法はありますか?

(私はjQueryベースの回答と「純粋なJS」の回答の両方に興味があります。)


1この投稿の以前の不運なバージョンは、ほぼ普遍的な理解の欠如、そして(もちろん)あまりにも典型的な反対票に直面しました。 1つの例外を除いて、私が得たすべてのコメントは投稿の前提そのものに異議を唱え、1つはイベント駆動型プログラミングなどの基本の理解に直接質問しました。少なくとも私が意味することの実用的な例を提示することによってそれを望んでいます私が言葉だけで説明したときほど、まったく考えられないことにはなりません。幸いなことに、以前の投稿で私が得た1つの有益なコメントは、関数jQuery.Callbacksについて私に知らせてくれました。これは確かに役立つヒントでした。投稿で言及されているスケッチの実装は、jQuery.Callbacksに基づいています。

9
kjo

大丈夫。

だから私はあなたができることはネイティブdispatchEventaddEventListenerを使うことだと思いますメソッドと使用documentpublishingsubscribeingの両方の唯一の要素として使用するそれらのイベントに。何かのようなもの:

var myCustomEvent = new Event('someEvent');
document.dispatchEvent(myCustomEvent);
...
document.addEventListener('someEvent', doSomething, false);

クロスブラウザを作成するには、次のことができます。

var myCustomEvent = new Event('someEvent');
document.dispatchEvent(myCustomEvent);
...
if (document.addEventListener) {
    document.addEventListener('someEvent', doSomething, false);
} else {
    document.attachEvent('someEvent', doSomething);
}

あなたは主題についてもっと読むことができます ここここ 。お役に立てれば。

15
Tahir Ahmed

私の質問は、カスタムイベントを「ブロードキャスト」するこの効果を実現するためのより良い(または少なくともより標準的な)方法はありますか?

いいえ、Javascriptでパブリッシュ/サブスクライブを行うためのより標準的な方法はありません。言語やブラウザに直接組み込まれているわけではなく、私が知っているプラ​​ットフォーム標準もありません。

独自のシステムをまとめるには、いくつかのオプションがあります(そのほとんどは知っているようです)。

documentオブジェクトやwindowオブジェクト、または作成した新しいオブジェクトなどの特定のオブジェクトを選択して、jQueryの.on()および.trigger()を使用できます。そのオブジェクトは、パブリッシュ/サブスクライブのようなモデルをまとめるための中央クリアリングハウスとして機能します。必要に応じて、いくつかのユーティリティ関数にコーディングするだけで、そのオブジェクトの存在を実際の使用から隠すこともできます。

または、すでにご存知のように、jQuery.Callbacks機能を使用することもできます。 jQuery doc にはパブリッシュ/サブスクライブのサンプルコードもあります。

または、従来のパブリッシュ/サブスクライブモデルを提供するサードパーティライブラリを見つけることができます。

または、特定のイベントに関連付けられているコールバック関数のリストを保持するだけで、そのイベントがトリガーされたときに各コールバック関数を呼び出すことができるように、独自のコールバック関数を最初から作成することもできます。

2
jfriend00

これを行うためのjQuery方法を探してここに来た場合は、次のようになります。

イベントブロードキャスト/ディスパッチコードを追加:

構文:
$(<element-name>).trigger(<event-name>);

例:

_$.ajax({
    ...
    complete: function () {
        // signal to registered listeners that event has occured
        $(document).trigger("build_complete");
        ...
    }
});
_

イベントのリスナーを登録します:

構文:
$(<element-name>).on(<event-name>, function() {...});

例:

_$(document).on("build_complete", function () {
    NextTask.Init();
});
_

注:次のように実行すると、$(document).build_complete(function() {...});はエラーになります:Uncaught TypeError: $(...).build_complete is not a function

0
SNag