Editar : o problema abordado nesta resposta foi resolvido na versão 1.2.7 do angular.js . $broadcastagora evita borbulhar em escopos não registrados e roda tão rápido quanto $ emitem.

Então agora você pode:
- use a
$broadcastpartir do$rootScope
- ouça usando
$on do local$scope que precisa saber sobre o evento
Resposta original abaixo
Eu recomendo não usar $rootScope.$broadcast+, $scope.$onmas sim $rootScope.$emit+ $rootScope.$on. O primeiro pode causar sérios problemas de desempenho, conforme levantado pelo @numan. Isso ocorre porque o evento passará por todos os escopos.
No entanto, o último (usando $rootScope.$emit+ $rootScope.$on) não sofre com isso e pode, portanto, ser usado como um canal de comunicação rápido!
A partir da documentação angular de $emit:
Distribui um nome de evento para cima pela hierarquia de escopo, notificando o registro
Como não há escopo acima $rootScope, não há bolhas acontecendo. É totalmente seguro usar $rootScope.$emit()/ $rootScope.$on()como um EventBus.
No entanto, há um problema ao usá-lo nos Controladores. Se você se vincular diretamente a $rootScope.$on()partir de dentro de um controlador, precisará limpar a ligação quando seu local $scopefor destruído. Isso ocorre porque os controladores (em contraste com os serviços) podem ser instanciados várias vezes ao longo da vida útil de um aplicativo, o que resultaria em ligações que acabariam criando eventualmente vazamentos de memória em todo o lugar :)
Para cancelar o registro, basta ouvir em seu $scope's $destroyevento e, em seguida, chamar a função que foi devolvido pelo $rootScope.$on.
angular
.module('MyApp')
.controller('MyController', ['$scope', '$rootScope', function MyController($scope, $rootScope) {
var unbind = $rootScope.$on('someComponent.someCrazyEvent', function(){
console.log('foo');
});
$scope.$on('$destroy', unbind);
}
]);
Eu diria que isso não é realmente uma coisa específica angular, pois também se aplica a outras implementações do EventBus, que você precisa limpar os recursos.
No entanto, você pode facilitar sua vida para esses casos. Por exemplo, você pode usar o patch do macaco $rootScopee atribuir um $onRootScopeque assine os eventos emitidos no $rootScopemas também limpe diretamente o manipulador quando o local $scopefor destruído.
A maneira mais limpa de fazer o patch do macaco $rootScopepara fornecer esse $onRootScopemétodo seria através de um decorador (um bloco de execução provavelmente também funcionará bem, mas pssst, não conte a ninguém)
Para garantir que a $onRootScopepropriedade não apareça inesperada ao enumerar $scope, usamos Object.defineProperty()e configuramos enumerablecomo false. Lembre-se de que você pode precisar de um calço ES5.
angular
.module('MyApp')
.config(['$provide', function($provide){
$provide.decorator('$rootScope', ['$delegate', function($delegate){
Object.defineProperty($delegate.constructor.prototype, '$onRootScope', {
value: function(name, listener){
var unsubscribe = $delegate.$on(name, listener);
this.$on('$destroy', unsubscribe);
return unsubscribe;
},
enumerable: false
});
return $delegate;
}]);
}]);
Com este método, o código do controlador acima pode ser simplificado para:
angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);
Portanto, como resultado final de tudo isso, recomendo que você use $rootScope.$emit+ $scope.$onRootScope.
Aliás, estou tentando convencer a equipe angular a resolver o problema dentro do núcleo angular. Há uma discussão em andamento aqui: https://github.com/angular/angular.js/issues/4574
Aqui está um jsperf que mostra o quanto de um impacto de desempenho $broadcasttraz para a mesa em um cenário decente com apenas 100 $scope's.
http://jsperf.com/rootscope-emit-vs-rootscope-broadcast
