$ rootScope。$ broadcastと$ scope。$ emit


349

今の性能差ということ$broadcastとが$emit排除されている、好むために何らかの理由がある$scope.$emitには$rootScope.$broadcast

はい、そうです。

$emit スコープ階層(上向き)に制限されています-これは、設計に適合している場合は良いかもしれませんが、かなり恣意的な制限のようです。

$rootScope.$broadcastイベントに耳を傾けることを選択するすべての人に働きかけます。これは私の心の中でより賢明な制限です。

何か不足していますか?

編集:

答えを明確にするために、発送の方向は私が求めている問題ではありません。$scope.$emitイベントを上方向、および$scope.$broadcast下方向にディスパッチします。しかし、なぜ$rootScope.$broadcastすべての意図されたリスナーに到達するために常に使用しないのですか?


3
toddmotto.com/…すべて揃っている
Divya MV

回答:


1155

tl; dr (このtl; drは以下の@ sp00mの回答からのものです)

$emitイベントを上にディスパッチします... $broadcastイベントを下にディスパッチします

詳細説明

$rootScope.$emit他の$rootScopeリスナーだけがそれをキャッチできるようにします。これは、すべての人$scopeに取得させたくない場合に適しています。主に高レベルのコミュニケーション。大人が部屋で互いに話しているので、子供が聞こえないように考えてください。

$rootScope.$broadcastほとんどすべてがそれを聞くことができる方法です。これは、夕食の準備ができているので、家の誰もがそれを聞くと親が叫ぶのと同じです。

$scope.$emitあなたがそれ$scopeとそのすべての親を望み$rootScope、イベントを聞きたいときです。これは、自宅で両親に向かって泣き言を言う子供です(ただし、他の子供が聞くことができる食料品店ではありません)。

$scope.$broadcast用で$scope、それ自体とその子。これは、ぬいぐるみをささやく子供で、両親には聞こえません。


3
@NewDevその理由は、多くの場合、ページ上でスコープの繰り返しがあるためです。データの異なるインスタンスを表すスコープが2つ以上ある場合(たとえば、ページに患者レコードのリストがあり、それぞれに独自のスコープがある場合)、そのうちの1つだけを対象とするイベントをルートからブロードキャストすることはできません。スコープ。$rootScope可能な限りブロードキャストを回避すると、再利用性が向上します。
Tim Rogers、

4
あなたが言ったことは間違っていませんが、$ emitはドキュメントを子スコープに移動し、$ emitはドキュメントを親スコープに移動することを一般化する方法です。どちらも、現在のスコープにアタッチされているリスナーをトリガーします。
Eric

123
あなたが使った例は素晴らしいです!
Assaf

72
うわー!子供でも理解できる!すごい:)
ナバニーズ

3
完璧な例、説明が大好き
Robin-Hoodie 2015年

104

それらは同じ仕事をしていません。すべての子スコープにイベントを下向きにディスパッチする一方で、スコープ階層を通じて$emitイベントを上向きに$broadcastディスパッチします。


2
はい、私は質問でそのことを指摘しました(おそらく、発送の方向性を明確にすることができたはずです)。ただし、これはかなり恣意的な制限であることにも触れました。「リスナー」に到達できる場合、なぜこれを常に下向きにできないの$rootScopeですか?
New Dev

$ emitはスコープの子または兄弟スコープに影響を与えないためです。これらは、JavaScriptのイベント伝搬タイプ(キャプチャーとバブリング)にマップされるだけです。$ broadcastはキャプチャに使用され、$ emitはバブリングに使用されます。違いをかなりよく説明する、今では古く見える一風変わった記事があります:quirksmode.org/js/events_order.html
Alan L.

77

次のリンクから次のグラフィックを作成しました:https : //toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

Scope、rootScope、emit、broadcast

ご覧のとおり、$rootScope.$broadcastはよりも多くのリスナーをヒットしています$scope.$emit

また、$scope.$emitバブリング効果はキャンセルできますがキャンセル$rootScope.$broadcastできません。


24
矢がたくさん見えます。
火星ロバートソン

4
@MichalStefanow私は視覚的な回答のファンです:)
Maria Ines Parnisari

@mparnisari:。$放送(名前、引数) -ブロードキャスト、すべての子どもの$スコープによるダウンイベント$ EMIT(名前、引数) - 。エミット$ rootScopeを含むすべての親への$スコープ階層アップイベント
CodeMan

19

ここに画像の説明を入力してください

$ scope。$ emit:このメソッドは、イベントを上方向(子から親へ)にディスパッチします

ここに画像の説明を入力してください $ scope。$ broadcast:メソッドは、イベントを下方向(親から子)にすべての子コントローラーにディスパッチします。

ここに画像の説明を入力してください $ scope。$ on:メソッドは、イベントをリッスンするために登録します。そのイベントをリッスンしているすべてのコントローラーは、ブロードキャストの通知を受け取るか、子と親の階層のどこに適合するかに基づいて放出します。

$ emitイベントは、イベントをリッスンしている$ scopeのいずれかによってキャンセルできます。

$ onは「stopPropagation」メソッドを提供します。このメソッドを呼び出すことにより、イベントがそれ以上伝播しないようにすることができます。

プランカー:https ://embed.plnkr.co/0Pdrrtj3GEnMp2UpILp4/

兄弟スコープ(直接の親子階層にないスコープ)の場合、$ emitと$ broadcastは兄弟スコープと通信しません。

ここに画像の説明を入力してください

詳細については、http://yogeshtutorials.blogspot.in/2015/12/event-based-communication-between-angularjs-controllers.htmlを参照してください。


ソリューションへのリンクを歓迎しますが、それがなくても回答が役に立つことを確認してください。リンクの周りにコンテキストを追加して、他のユーザーがそれが何であるか、なぜそこにあるのかを理解し、ページの最も関連性の高い部分を引用してくださいターゲットページが利用できない場合にリンクし直します。リンクに過ぎない回答は削除される場合があります。
Baum mit Augen

目的は動作するプランカーを提供することでしたが、ここに適切な説明を追加しました。
Yogesh 2017年

3

@Eddieは、質問の完全な回答を提供しました。しかし、Pub / Subのより効率的なアプローチの使用に注意を向けたいと思います。

同様に、この答えは示唆しています、

$ broadcast / $ onアプローチは、すべてのスコープにブロードキャストするので(スコープ階層の一方または両方の方向に)非常に効率的ではありません。一方、Pub / Subのアプローチはより直接的です。サブスクライバーだけがイベントを取得するため、システム内のすべてのスコープでイベントが機能するわけではありません。

angular-PubSub角度モジュールを使用できます。PubSubアプリの依存関係にモジュールを追加すると、PubSubサービスを使用してイベント/トピックをサブスクライブおよびサブスクライブ解除できます。

簡単に登録:

// Subscribe to event
var sub = PubSub.subscribe('event-name', function(topic, data){

});

公開が簡単

PubSub.publish('event-name', {
    prop1: value1,
    prop2: value2
});

退会するには、PubSub.unsubscribe(sub);ORを使用しますPubSub.unsubscribe('event-name');

注意メモリリークを回避するために、サブスクライブ解除を忘れないでください。


2

サービスでRxJSを使用する

たとえば、サービスが状態を保持している状況ではどうでしょうか。そのサービスへの変更をプッシュするにはどうすればよいですか。また、ページ上の他のランダムコンポーネントはそのような変更を認識できますか?最近この問題に取り組むことに苦労している

Angular用のRxJS拡張を使用してサービスを構築します。

<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/rx/dist/rx.all.js"></script>
<script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>
var app = angular.module('myApp', ['rx']);

app.factory("DataService", function(rx) {
  var subject = new rx.Subject(); 
  var data = "Initial";

  return {
      set: function set(d){
        data = d;
        subject.onNext(d);
      },
      get: function get() {
        return data;
      },
      subscribe: function (o) {
         return subject.subscribe(o);
      }
  };
});

次に、単に変更をサブスクライブします。

app.controller('displayCtrl', function(DataService) {
  var $ctrl = this;

  $ctrl.data = DataService.get();
  var subscription = DataService.subscribe(function onNext(d) {
      $ctrl.data = d;
  });

  this.$onDestroy = function() {
      subscription.dispose();
  };
});

クライアントはで変更をサブスクライブできDataService.subscribe、プロデューサーはで変更をプッシュできますDataService.set

PLNKR上のDEMO

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.