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

349

Maintenant que la différence de performance entre $broadcastet $emita été éliminé, est - il une raison de préférer $scope.$emità $rootScope.$broadcast?

Ils sont différents, oui.

$emit est limité à la hiérarchie des portées (vers le haut) - cela peut être bien, si cela correspond à votre conception, mais cela me semble une restriction plutôt arbitraire.

$rootScope.$broadcastfonctionne à travers tous ceux qui choisissent d'écouter l'événement, ce qui est une restriction plus sensible dans mon esprit.

Suis-je en train de manquer quelque chose?

ÉDITER:

Pour clarifier en réponse à une réponse, la direction de l'envoi n'est pas le problème que je recherche. $scope.$emitrépartit l'événement vers le haut et $scope.$broadcast- vers le bas. Mais pourquoi ne pas toujours utiliser $rootScope.$broadcastpour atteindre tous les auditeurs visés?

New Dev
la source
3
toddmotto.com/… a tout pour plaire
Divya MV

Réponses:

1155

tl; dr (ce tl; dr provient de la réponse de @ sp00m ci-dessous)

$emitdistribue un événement vers le haut ... $broadcastdistribue un événement vers le bas

Explication détaillée

$rootScope.$emitpermet seulement aux autres $rootScopeauditeurs de l'attraper. C'est bien quand vous ne voulez pas que tout $scopele monde l'obtienne. Surtout une communication de haut niveau. Considérez-le comme des adultes qui se parlent dans une pièce pour que les enfants ne puissent pas les entendre.

$rootScope.$broadcastest une méthode qui permet à peu près tout de l'entendre. Ce serait l'équivalent de parents criant que le dîner est prêt pour que tout le monde dans la maison l'entende.

$scope.$emitc'est quand vous voulez ça $scopeet tous ses parents et $rootScopeentendre l'événement. Il s'agit d'un enfant pleurnichant à ses parents à la maison (mais pas dans une épicerie où d'autres enfants peuvent entendre).

$scope.$broadcastest pour $scopelui - même et ses enfants. C'est un enfant qui chuchote à ses animaux en peluche pour que leurs parents n'entendent pas.

Eddie Monge Jr
la source
3
@NewDev La raison en est que vous avez souvent des répétitions de portées sur la page. Si vous avez deux ou plusieurs étendues représentant différentes instances de données - par exemple une liste d'enregistrements de patients sur une page, chacune avec sa propre étendue - alors il ne fonctionnera pas pour diffuser à partir de la racine un événement destiné à un seul de ceux portées. Si $rootScopepossible, éviter les émissions permet une meilleure réutilisation.
Tim Rogers
4
Rien de ce que vous avez dit n'est faux, mais un moyen de généraliser que $ emit descend le document vers les étendues enfants et $ emit monte le document vers les étendues parent. Les deux déclenchent tous les écouteurs attachés à la portée actuelle.
Eric
123
L'exemple que vous avez utilisé est génial!
Assaf
72
Hou la la! Même les enfants peuvent comprendre cela! Incroyable :)
Navaneeth
3
Exemple parfait, j'adore l'explication
Robin-Hoodie
104

Ils ne font pas le même travail: $emitdistribue un événement vers le haut à travers la hiérarchie d'étendue, tandis que $broadcastdistribue un événement vers le bas à toutes les étendues enfants.

sp00m
la source
2
Oui, je l'ai noté dans la question (j'aurais peut-être pu préciser la direction de l'envoi). Mais j'ai également noté qu'il s'agit d'une restriction plutôt arbitraire. Si je peux atteindre mon "auditeur", pourquoi ne puis-je pas toujours le faire vers le bas à partir de $rootScope?
Nouveau développeur
Parce qu'un $ emit n'affectera pas les étendues enfant ou frère d'une étendue. Ceux-ci sont simplement mappés aux types de propagation d'événements de javascript - capture et propagation. $ broadcast est utilisé pour la capture et $ emit est utilisé pour le bullage. Il y a maintenant un article quirksmode apparemment ancien qui explique assez bien la différence: quirksmode.org/js/events_order.html
Alan L.
77

J'ai créé le graphique suivant à partir du lien suivant: https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

Scope, rootScope, emit, broadcast

Comme vous pouvez le voir, $rootScope.$broadcastfrappe beaucoup plus d'auditeurs que $scope.$emit.

De plus, $scope.$emitl'effet bouillonnant de peut être annulé, alors $rootScope.$broadcastqu'il ne le peut pas.

Maria Ines Parnisari
la source
24
Je vois beaucoup de flèches.
Mars Robertson
4
@MichalStefanow Je suis fan de réponses visuelles :)
Maria Ines Parnisari
@mparnisari:. $ broadcast (name, args) - Diffusez un événement dans l'étendue $ de tous les enfants. $ emit (name, args) - Emettez un événement dans la hiérarchie $ scope à tous les parents, y compris $ rootScope
CodeMan
19

entrez la description de l'image ici

$ scope. $ emit: cette méthode distribue l'événement vers le haut (de l'enfant au parent)

entrez la description de l'image ici $ scope. $ broadcast: la méthode distribue l'événement dans le sens descendant (du parent à l'enfant) à tous les contrôleurs enfants.

entrez la description de l'image ici $ scope. $ on: La méthode s'inscrit pour écouter un événement. Tous les contrôleurs qui écoutent cet événement reçoivent une notification de la diffusion ou émettent en fonction de leur place dans la hiérarchie enfant-parent.

L'événement $ emit peut être annulé par n'importe qui de la portée $ qui écoute l'événement.

$ On fournit la méthode "stopPropagation". En appelant cette méthode, il est possible d'empêcher la propagation de l'événement.

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

Dans le cas de portées frère (les portées qui ne sont pas dans la hiérarchie parent-enfant directe), $ emit et $ broadcast ne communiqueront pas avec les portées frère.

entrez la description de l'image ici

Pour plus de détails, veuillez consulter http://yogeshtutorials.blogspot.in/2015/12/event-based-communication-between-angularjs-controllers.html

Yogesh
la source
Un lien vers une solution est le bienvenu, mais assurez-vous que votre réponse est utile sans elle: ajoutez du contexte autour du lien pour que vos collègues aient une idée de ce que c'est et pourquoi il est là, puis citez la partie la plus pertinente de la page que vous '' relier à au cas où la page cible n'est pas disponible. Les réponses qui ne sont guère plus qu'un lien peuvent être supprimées.
Baum mit Augen
L'objectif était de fournir le plongeur de travail, cependant, j'ai ajouté la description appropriée ici.
Yogesh
3

@Eddie a donné une réponse parfaite à la question posée. Mais je voudrais attirer l'attention sur l'utilisation d'une approche plus efficace de Pub / Sub.

Comme suggère cette réponse,

L'approche $ broadcast / $ on n'est pas très efficace car elle diffuse sur toutes les portées (soit dans un sens, soit dans les deux sens de la hiérarchie des portées). Alors que l'approche Pub / Sub est beaucoup plus directe. Seuls les abonnés reçoivent les événements, donc cela ne va pas dans toutes les étendues du système pour le faire fonctionner.

vous pouvez utiliser un angular-PubSubmodule angulaire. une fois que vous ajoutezPubSub module à la dépendance de votre application, vous pouvez utiliser le PubSubservice pour vous abonner et vous désabonner des événements / sujets.

Inscription facile:

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

});

Facile à publier

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

Pour vous désinscrire, utilisez PubSub.unsubscribe(sub);OR PubSub.unsubscribe('event-name');.

REMARQUE N'oubliez pas de vous désabonner pour éviter les fuites de mémoire.

vigne
la source
2

Utiliser RxJS dans un service

Qu'en est-il dans une situation où vous avez un service qui tient l'état par exemple. Comment est-ce que je pourrais pousser des changements à ce service, et d'autres composants aléatoires sur la page sont au courant d'un tel changement? J'ai eu du mal à résoudre ce problème récemment

Créez un service avec les extensions RxJS pour 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);
      }
  };
});

Il vous suffit ensuite de vous abonner aux modifications.

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

Les clients peuvent souscrire aux modifications avec DataService.subscribeet les producteurs peuvent pousser les modifications avec DataService.set.

La DEMO sur PLNKR .

georgeawg
la source