$ rootScope. $ broadcast vs. $ scope. $ emit

349

Teraz, że różnica wydajności pomiędzy $broadcasti $emitzostała wyeliminowana, nie ma żadnych powodów, aby wolą $scope.$emitsię $rootScope.$broadcast?

Są różne, tak.

$emit jest ograniczona do hierarchii zakresu (w górę) - może to być dobre, jeśli pasuje do twojego projektu, ale wydaje mi się to dość arbitralnym ograniczeniem.

$rootScope.$broadcastdziała we wszystkich, którzy zdecydują się słuchać tego wydarzenia, co jest bardziej rozsądnym ograniczeniem w mojej opinii.

Czy coś brakuje?

EDYTOWAĆ:

Aby wyjaśnić w odpowiedzi na odpowiedź, nie chodzi o kierunek wysyłki. $scope.$emitwywołuje zdarzenie w górę, i $scope.$broadcast- w dół. Ale dlaczego nie zawsze $rootScope.$broadcastdocierać do wszystkich zamierzonych słuchaczy?

New Dev
źródło
3
toddmotto.com/… ma to wszystko
Divya MV

Odpowiedzi:

1155

tl; dr (ten tl; dr pochodzi z odpowiedzi @ sp00m poniżej)

$emitwywołuje zdarzenie w górę ... $broadcastwywołuje zdarzenie w dół

Szczegółowe wyjaśnienie

$rootScope.$emitpozwala tylko innym $rootScopesłuchaczom go złapać. Jest to dobre, gdy nie chcesz, $scopeaby każdy to otrzymał. Przeważnie komunikacja na wysokim poziomie. Pomyśl o tym, jak dorośli rozmawiają ze sobą w pokoju, aby dzieci ich nie słyszały.

$rootScope.$broadcastto metoda, która pozwala usłyszeć prawie wszystko. Byłoby to odpowiednikiem krzyku rodziców, że obiad jest gotowy, więc wszyscy w domu to słyszą.

$scope.$emitjest to, kiedy chcesz tego $scopei wszystkich jego rodziców i $rootScopeusłyszeć wydarzenie. To dziecko narzeka na rodziców w domu (ale nie w sklepie spożywczym, w którym słyszą inne dzieci).

$scope.$broadcastjest dla $scopesiebie i swoich dzieci. To dziecko szepcze pluszowym zwierzakom, żeby ich rodzice nie słyszeli.

Eddie Monge Jr
źródło
3
@NewDev Powodem jest to, że często na stronie powtarzają się zakresy. Jeśli masz dwa lub więcej zakresów reprezentujących różne instancje danych - np. Listę rekordów pacjentów na stronie, każdy z własnym zakresem - nie będzie działać transmisja z katalogu głównego zdarzenia przeznaczonego tylko dla jednego z nich zakresy Unikanie $rootScopetransmisji tam, gdzie to możliwe, umożliwia lepsze ponowne wykorzystanie.
Tim Rogers,
4
Nic, co powiedziałeś, nie jest złe, ale sposób na uogólnienie, że $ emituje dokument do zakresów potomnych, a $ emituje dokument do zakresów nadrzędnych. Oba wyzwalają wszystkich detektorów podłączonych do bieżącego zakresu.
Eric
123
Użyty przykład jest świetny!
Assaf
72
Łał! Nawet dzieci mogą to zrozumieć! Niesamowite :)
Navaneeth
3
Idealny przykład, uwielbiam wyjaśnienie
Robin-Hoodie
104

Nie wykonują tego samego zadania: $emitwywołują zdarzenie w górę poprzez hierarchię zasięgu, a $broadcastzdarzenie w dół do wszystkich zakresów potomnych.

sp00m
źródło
2
Tak, zauważyłem to w pytaniu (być może mógłbym jasno powiedzieć o kierunku wysyłki). Ale zauważyłem również, że jest to raczej arbitralne ograniczenie. Jeśli mogę dotrzeć do mojego „słuchacza”, dlaczego nie zawsze mogę to zrobić w dół $rootScope?
Nowy Dev,
Ponieważ emisja $ nie wpłynie na zakresy potomne lub siostrzane zakresu. Po prostu odwzorowują typy propagacji zdarzeń w javascript - przechwytywanie i propagowanie. $ broadcast służy do przechwytywania, a $ emit służy do propagacji. Jest na pozór starożytny artykuł quirksmode, który całkiem dobrze wyjaśnia różnicę: quirksmode.org/js/events_order.html
Alan L.
77

Wykonałem następującą grafikę z następującego linku: https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

Zakres, rootScope, emisja, emisja

Jak widać, $rootScope.$broadcasttrafia o wiele więcej słuchaczy niż $scope.$emit.

Również $scope.$emitefekt bulgotania można anulować, $rootScope.$broadcastale nie można.

Maria Ines Parnisari
źródło
24
Widzę dużo strzał.
Mars Robertson,
4
@MichalStefanow Jestem fanem wizualnych odpowiedzi :)
Maria Ines Parnisari
@mparnisari:. $ broadcast (nazwa, argumenty) - Transmisja zdarzenia w dół do zakresu $ wszystkich dzieci. $ emit (nazwa, argumenty) - Emisja zdarzenia w górę hierarchii $ do wszystkich rodziców, w tym $ rootScope
CodeMan
19

wprowadź opis zdjęcia tutaj

$ scope. $ emit: Ta metoda wywołuje zdarzenie w górę (od dziecka do rodzica)

wprowadź opis zdjęcia tutaj $ scope. $ broadcast: Metoda wywołuje zdarzenie w dół (od rodzica do dziecka) do wszystkich kontrolerów potomnych.

wprowadź opis zdjęcia tutaj $ scope. $ on: Metoda rejestruje się w celu odsłuchania jakiegoś zdarzenia. Wszystkie kontrolery, które nasłuchują tego zdarzenia, otrzymują powiadomienie o emisji lub emitują na podstawie tego, gdzie mieszczą się one w hierarchii dziecko-rodzic.

Zdarzenie $ emit może zostać anulowane przez każdego z $ zakres, który nasłuchuje zdarzenia.

$ On zapewnia metodę „stopPropagation”. Wywołanie tej metody może uniemożliwić dalszą propagację zdarzenia.

Plunker: https://embed.plnkr.co/0Pdrrtj3GEnMp2UpILp4/

W przypadku zakresów rodzeństwa (zakresów, które nie znajdują się w bezpośredniej hierarchii rodzic-dziecko), wówczas $ emit i $ broadcast nie będą komunikować się z zasięgami rodzeństwa.

wprowadź opis zdjęcia tutaj

Więcej informacji można znaleźć na stronie http://yogeshtutorials.blogspot.in/2015/12/event-based-communication-between-angularjs-controllers.html

Jogesh
źródło
Link do rozwiązania jest mile widziany, ale upewnij się, że Twoja odpowiedź jest przydatna bez niego: dodaj kontekst wokół linku, aby inni użytkownicy mieli pojęcie, co to jest i dlaczego tam jest, a następnie zacytuj najbardziej odpowiednią część strony, którą „ ponowne linkowanie na wypadek, gdyby strona docelowa była niedostępna. Odpowiedzi, które są niewiele więcej niż link, mogą zostać usunięte.
Baum mit Augen
Celem było zapewnienie działającego plunkera, jednak dodałem tutaj odpowiedni opis.
Jogesh
3

@Eddie udzielił idealnej odpowiedzi na zadane pytanie. Chciałbym jednak zwrócić uwagę na bardziej wydajne podejście Pub / Sub.

Jak sugeruje ta odpowiedź,

Podejście $ broadcast / $ on nie jest zbyt wydajne, ponieważ nadaje do wszystkich zakresów (albo w jednym kierunku, albo w obu kierunkach hierarchii zakresu). Podczas gdy podejście Pub / Sub jest znacznie bardziej bezpośrednie. Tylko subskrybenci odbierają zdarzenia, więc nie musi działać w każdym zakresie w systemie.

możesz użyć angular-PubSubmodułu kątowego. po dodaniu PubSubmodułu do zależności aplikacji możesz użyć PubSubusługi do subskrybowania i anulowania subskrypcji wydarzeń / tematów.

Łatwa subskrypcja:

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

});

Łatwe do opublikowania

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

Aby anulować subskrypcję, użyj PubSub.unsubscribe(sub); LUB PubSub.unsubscribe('event-name');.

UWAGA Nie zapomnij anulować subskrypcji, aby uniknąć wycieków pamięci.

vinesh
źródło
2

Użyj RxJS w usłudze

A może na przykład w sytuacji, gdy masz usługę, która utrzymuje stan. Jak mogę wcisnąć zmiany w tej usłudze, a inne losowe komponenty na stronie powinny wiedzieć o takiej zmianie? Ostatnio zmagam się z rozwiązaniem tego problemu

Zbuduj usługę z rozszerzeniami RxJS dla Angular .

<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);
      }
  };
});

Następnie subskrybuj zmiany.

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();
  };
});

Klienci mogą subskrybować zmiany za pomocą, DataService.subscribea producenci mogą wprowadzać zmiany za pomocą DataService.set.

DEMO na PLNKR .

georgeawg
źródło