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

349

Ahora que la diferencia de rendimiento entre $broadcasty $emitha sido eliminado, ¿hay alguna razón para preferir $scope.$emita $rootScope.$broadcast?

Son diferentes, si.

$emit está restringido a la jerarquía del alcance (hacia arriba): esto puede ser bueno si se ajusta a su diseño, pero me parece una restricción bastante arbitraria.

$rootScope.$broadcastfunciona en todos los que eligen escuchar el evento, lo cual es una restricción más sensata en mi mente.

¿Me estoy perdiendo de algo?

EDITAR:

Para aclarar en respuesta a una respuesta, la dirección del envío no es el problema que busco. $scope.$emitdespacha el evento hacia arriba y $scope.$broadcast- hacia abajo. Pero, ¿por qué no usar siempre $rootScope.$broadcastpara llegar a todos los oyentes previstos?

New Dev
fuente
3
toddmotto.com/… lo tiene todo
Divya MV

Respuestas:

1155

tl; dr (este tl; dr es de la respuesta de @ sp00m a continuación)

$emitdespacha un evento hacia arriba ... $broadcastdespacha un evento hacia abajo

Explicación detallada

$rootScope.$emitsolo deja que otros $rootScopeoyentes lo atrapen. Esto es bueno cuando no quieres que todos lo $scopetengan. Principalmente una comunicación de alto nivel. Piense en ello como adultos hablando entre ellos en una habitación para que los niños no puedan escucharlos.

$rootScope.$broadcastes un método que permite que casi todo lo escuche. Esto sería el equivalente a que los padres griten que la cena está lista para que todos en la casa la escuchen.

$scope.$emites cuando quieres eso $scopey todos sus padres y $rootScopeescuchar el evento. Este es un niño que se queja a sus padres en casa (pero no en una tienda de abarrotes donde otros niños pueden escuchar).

$scope.$broadcastes para el $scopemismo y sus hijos. Este es un niño susurrando a sus animales de peluche para que sus padres no puedan escuchar.

Eddie Monge Jr
fuente
3
@NewDev La razón es porque a menudo tiene repetición de ámbitos en la página. Si tiene dos o más ámbitos que representan diferentes instancias de datos, por ejemplo, una lista de registros de pacientes en una página, cada uno con su propio alcance, entonces no funcionará transmitir desde la raíz un evento destinado solo a uno de esos alcances Evitar $rootScopetransmisiones donde sea posible permite una mejor reutilización.
Tim Rogers
44
Nada de lo que ha dicho está mal, pero una forma de generalizarlo es que $ emit baja el documento a ámbitos secundarios y $ emit sube el documento a ámbitos primarios. Ambos activarán a los oyentes conectados al alcance actual.
Eric
123
¡El ejemplo que usaste es genial!
Assaf
72
¡Guauu! ¡Incluso los niños pueden entender esto! Increíble :)
Navaneeth
3
Ejemplo perfecto, me encanta la explicación
Robin-Hoodie
104

No están haciendo el mismo trabajo: $emitdistribuye un evento hacia arriba a través de la jerarquía de alcance, mientras que $broadcastdistribuye un evento hacia abajo a todos los ámbitos secundarios.

sp00m
fuente
2
Sí, noté eso en la pregunta (tal vez podría haber dejado en claro la dirección del envío). Pero también noté que esa es una restricción bastante arbitraria. Si puedo llegar a mi "oyente", ¿por qué no puedo hacer esto siempre hacia abajo $rootScope?
Nuevo desarrollador
Porque un $ emit no afectará los ámbitos secundarios o secundarios de un osciloscopio. Estos solo se asignan a los tipos de propagación de eventos de JavaScript: captura y burbujeo. $ broadcast se usa para capturar y $ emit se usa para burbujear. Hay un artículo de quirksmode ahora aparentemente antiguo que explica la diferencia bastante bien: quirksmode.org/js/events_order.html
Alan L.
77

Hice el siguiente gráfico con el siguiente enlace: https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

Alcance, rootScope, emitir, transmitir

Como puede ver, $rootScope.$broadcastllega a muchos más oyentes que $scope.$emit.

Además, $scope.$emitel efecto de burbujeo se puede cancelar, mientras $rootScope.$broadcastque no se puede.

Maria Ines Parnisari
fuente
24
Veo muchas flechas.
Mars Robertson
44
@MichalStefanow Soy fanática de las respuestas visuales :)
Maria Ines Parnisari
@mparnisari:. $ broadcast (name, args) - Transmite un evento hacia abajo a través del $ alcance de todos los hijos. $ emit (name, args) - Emite un evento hacia arriba en la jerarquía de $ alcance para todos los padres, incluido el $ rootScope
CodeMan
19

ingrese la descripción de la imagen aquí

$ scope. $ emit: este método distribuye el evento en dirección ascendente (de secundario a primario)

ingrese la descripción de la imagen aquí $ scope. $ broadcast: Method distribuye el evento en dirección descendente (de padre a hijo) a todos los controladores secundarios.

ingrese la descripción de la imagen aquí $ scope. $ on: el método se registra para escuchar algún evento. Todos los controladores que están escuchando ese evento reciben una notificación de la emisión o emisión en función de dónde encajan en la jerarquía de elementos primarios y secundarios.

El evento $ emit puede ser cancelado por cualquiera de los $ scope que está escuchando el evento.

$ On proporciona el método "stopPropagation". Al llamar a este método, se puede detener la propagación del evento.

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

En el caso de ámbitos hermanos (los ámbitos que no están en la jerarquía directa padre-hijo), $ emit y $ broadcast no se comunicarán con los ámbitos hermanos.

ingrese la descripción de la imagen aquí

Para obtener más detalles, consulte http://yogeshtutorials.blogspot.in/2015/12/event-based-communication-between-angularjs-controllers.html

Yogesh
fuente
Un enlace a una solución es bienvenido, pero asegúrese de que su respuesta sea útil sin él: agregue contexto alrededor del enlace para que sus otros usuarios tengan una idea de qué es y por qué está allí, luego cite la parte más relevante de la página volver a vincular en caso de que la página de destino no esté disponible. Se pueden eliminar las respuestas que son poco más que un enlace.
Baum mit Augen
El objetivo era proporcionar el plunker de trabajo, sin embargo, he agregado la descripción adecuada aquí.
Yogesh
3

@Eddie ha dado una respuesta perfecta a la pregunta formulada. Pero me gustaría llamar la atención sobre el uso de un enfoque más eficiente de Pub / Sub.

Como sugiere esta respuesta,

El enfoque $ broadcast / $ on no es terriblemente eficiente, ya que transmite a todos los ámbitos (ya sea en una dirección o en ambas direcciones de la jerarquía de Scope). Mientras que el enfoque Pub / Sub es mucho más directo. Solo los suscriptores obtienen los eventos, por lo que no va a todos los ámbitos del sistema para que funcione.

Puedes usar angular-PubSubel módulo angular. una vez que agregue el PubSubmódulo a la dependencia de su aplicación, puede usarPubSub servicio para suscribirse y cancelar eventos / temas.

Fácil de suscribir:

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

});

Fácil de publicar

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

Para cancelar la suscripción, use PubSub.unsubscribe(sub);OR PubSub.unsubscribe('event-name');.

NOTA No olvide darse de baja para evitar pérdidas de memoria.

vinesh
fuente
2

Use RxJS en un servicio

¿Qué pasa en una situación en la que tiene un Servicio que tiene el estado en espera, por ejemplo? ¿Cómo podría enviar cambios a ese Servicio, y otros componentes aleatorios en la página estar al tanto de tal cambio? He estado luchando para abordar este problema últimamente

Cree un servicio con RxJS Extensions para 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);
      }
  };
});

Luego simplemente suscríbase a los cambios.

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

Los clientes pueden suscribirse a los cambios con DataService.subscribey los productores pueden impulsar los cambios con DataService.set.

La DEMO en PLNKR .

georgeawg
fuente