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

349

Agora que a diferença de desempenho entre $broadcaste $emitfoi eliminada, há alguma razão para preferir $scope.$emita $rootScope.$broadcast?

Eles são diferentes, sim.

$emit está restrito à hierarquia de escopo (para cima) - isso pode ser bom, se for adequado ao seu design, mas me parece uma restrição bastante arbitrária.

$rootScope.$broadcastfunciona em todos os que escolhem ouvir o evento, o que é uma restrição mais sensata em minha mente.

Estou esquecendo de algo?

EDITAR:

Para esclarecer em resposta a uma resposta, a direção da expedição não é o problema que estou procurando. $scope.$emitdespacha o evento para cima e $scope.$broadcastpara baixo. Mas por que não usar sempre $rootScope.$broadcastpara alcançar todos os ouvintes pretendidos?

New Dev
fonte
3
toddmotto.com/… tem tudo #
Divya MV

Respostas:

1155

tl; dr (este tl; dr é da resposta de @ sp00m abaixo)

$emitdespacha um evento para cima ... $broadcastdespacha um evento para baixo

Explicação detalhada

$rootScope.$emitapenas permite que outros $rootScopeouvintes o capturem. Isso é bom quando você não quer que todos $scopeobtenham. Principalmente uma comunicação de alto nível. Pense nisso como adultos conversando em uma sala para que as crianças não possam ouvi-los.

$rootScope.$broadcasté um método que permite que praticamente tudo o ouça. Isso seria o equivalente a pais gritando que o jantar está pronto para que todos na casa o ouçam.

$scope.$emité quando você quer isso $scopee todos os seus pais e $rootScopeouvir o evento. É uma criança choramingando para os pais em casa (mas não em um supermercado onde outras crianças possam ouvir).

$scope.$broadcasté para $scopesi e seus filhos. É uma criança sussurrando para seus bichos de pelúcia para que seus pais não possam ouvir.

Eddie Monge Jr
fonte
3
@NewDev O motivo é que muitas vezes você tem repetição de escopos na página. Se você tiver dois ou mais escopos representando diferentes instâncias de dados - por exemplo, uma lista de registros de pacientes em uma página, cada um com seu próprio escopo -, não funcionará para transmitir da raiz um evento destinado a apenas um deles. escopos. Evitar $rootScopetransmissões sempre que possível permite uma melhor reutilização.
Tim Rogers
4
Nada do que você disse está errado, mas uma maneira de generalizar que $ emit diminui o documento para escopos filho e $ emit aumenta o documento para escopos pai. Ambos acionarão todos os ouvintes conectados ao escopo atual.
1176 Eric Eric
123
O exemplo que você usou é ótimo!
Assaf
72
Uau! Até as crianças podem entender isso! :) incrível
Navaneeth
3
Exemplo perfeito, amo a explicação
Robin-Hoodie
104

Eles não estão fazendo o mesmo trabalho: $emitdespacha um evento para cima através da hierarquia de escopo, enquanto $broadcastdespacha um evento para baixo para todos os escopos filhos.

sp00m
fonte
2
Sim, observei isso na pergunta (talvez eu pudesse ter deixado claro sobre a direção da expedição). Mas também observei que essa é uma restrição bastante arbitrária. Se posso alcançar meu "ouvinte", por que não consigo sempre fazer isso de baixo para baixo $rootScope?
Nova Dev
Porque um $ emit não afetará os escopos filho ou irmão de um escopo. Eles são mapeados apenas para os tipos de propagação de eventos do javascript - capturando e borbulhando. $ broadcast é usado para capturar e $ emit são usados ​​para borbulhar. Há um artigo quirksmode agora aparentemente antigo que explica a diferença muito bem: quirksmode.org/js/events_order.html
Alan L.
77

Criei o seguinte gráfico a partir do seguinte link: https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

Escopo, rootScope, emitir, transmitir

Como você pode ver, $rootScope.$broadcastatinge muito mais ouvintes do que $scope.$emit.

Além disso, $scope.$emito efeito de bolha do pode ser cancelado, enquanto $rootScope.$broadcastnão pode.

Maria Ines Parnisari
fonte
24
Eu vejo muitas flechas.
Mars Robertson
4
@MichalStefanow Eu sou um fã de respostas visuais :)
Maria Ines Parnisari
@mparnisari:. $ broadcast (nome, args) -. Transmissão um evento para baixo através do $ âmbito de todas as crianças $ Emit (nome, args) - Emit um evento para cima na hierarquia $ âmbito a todos os pais, incluindo os US $ rootScope
CodeMan
19

insira a descrição da imagem aqui

$ scope. $ emit: este método despacha o evento na direção ascendente (do filho para o pai)

insira a descrição da imagem aqui $ scope. $ broadcast: o método despacha o evento na direção descendente (de pai para filho) para todos os controladores filhos.

insira a descrição da imagem aqui $ scope. $ on: o método é registrado para ouvir algum evento. Todos os controladores que estão ouvindo esse evento recebem uma notificação da transmissão ou emitem com base no local em que eles se encaixam na hierarquia pai-filho.

O evento $ emit pode ser cancelado por qualquer um dos escopos $ que estiver ouvindo o evento.

O $ on fornece o método "stopPropagation". Ao chamar esse método, o evento pode ser impedido de se propagar mais.

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

No caso de escopos irmãos (os escopos que não estão na hierarquia pai-filho direta), $ emitem e $ broadcast não se comunicam com os escopos irmãos.

insira a descrição da imagem aqui

Para obter mais detalhes, consulte http://yogeshtutorials.blogspot.in/2015/12/event-based-communication-between-angularjs-controllers.html

Yogesh
fonte
Um link para uma solução é bem-vindo, mas garanta que sua resposta seja útil sem ela: adicione contexto ao link para que seus colegas usuários tenham uma idéia do que é e por que está lá, depois cite a parte mais relevante da página que você ' reencaminhando para o caso de a página de destino estar indisponível. Respostas que são pouco mais que um link podem ser excluídas.
Baum mit Augen
O objetivo era fornecer o plunker de trabalho, no entanto, adicionei a descrição apropriada aqui.
precisa
3

@ Eddie deu uma resposta perfeita da pergunta. Mas eu gostaria de chamar a atenção para o uso de uma abordagem mais eficiente do Pub / Sub.

Como essa resposta sugere,

A abordagem $ broadcast / $ on não é terrivelmente eficiente, pois é transmitida para todos os escopos (em uma direção ou em ambas as direções da hierarquia do escopo). Enquanto a abordagem Pub / Sub é muito mais direta. Somente os assinantes recebem os eventos; portanto, não é necessário que todos os escopos do sistema funcionem.

você pode usar angular-PubSubo módulo angular. depois de adicionar o PubSubmódulo à dependência do aplicativo, você pode usar o PubSubserviço para assinar e cancelar a inscrição de eventos / tópicos.

Fácil de se inscrever:

// 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 a inscrição, use PubSub.unsubscribe(sub);OR PubSub.unsubscribe('event-name');.

NOTA Não se esqueça de cancelar a inscrição para evitar vazamentos de memória.

vinha
fonte
2

Use RxJS em um serviço

E em uma situação em que você tem um Serviço que está mantendo o estado, por exemplo. Como eu poderia enviar alterações para esse Serviço e outros componentes aleatórios na página estar cientes dessa alteração? Ultimamente, tenho lutado para resolver esse problema

Crie um serviço com RxJS Extensions for 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);
      }
  };
});

Em seguida, basta assinar as alterações.

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

Os clientes podem assinar alterações DataService.subscribee os produtores podem enviar alterações com DataService.set.

A DEMO em PLNKR .

georgeawg
fonte