Edit: El problema abordado en esta respuesta ha sido solucionado en las últimas versiones de angular.js $broadcast
ahora evita burbujas más no registrados ámbitos y corre tan rápido como $emiten.
Lo recomiendo encarecidamente no usar $rootScope.$broadcast
+ $scope.$on
, sino $rootScope.$emit
+ $rootScope.$on
. El primero puede causar serios problemas de rendimiento planteados por @numan. Eso es debido a que el evento se burbuja hacia abajo a través de todos los ámbitos.
Sin embargo, el segundo (utilizando $rootScope.$emit
+ $rootScope.$on
) ¿ no sufren de este y por lo tanto puede ser utilizado como un canal de comunicación rápido!
Desde el ángulo de la documentación de $emit
:
Distribuye un evento nombre hacia arriba a través de la jerarquía de ámbito notificar a la registrada
Ya que no hay ámbito supra $rootScope
, no hay ningún burbujeo sucediendo. Es totalmente seguro para el uso $rootScope.$emit()
/ $rootScope.$on()
como EventBus.
Sin embargo, hay un problema cuando se utiliza dentro de los Controladores. Si se unen directamente a $rootScope.$on()
desde dentro de un controlador, usted tendrá que limpiar el enlace cuando el local $scope
se destruye. Esto es debido a que los controladores (en contraste a los servicios) puede ser instanciado varias veces durante la vida útil de una aplicación que podría resultar en enlaces resumiendo, finalmente, la creación de fugas de memoria en todo el lugar :)
Para anular el registro, acabo de escuchar en su $scope
s' $destroy
evento y, a continuación, llamar a la función que devolvió $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);
}
]);
Quiero decir que, realmente, no es un angular de la cosa específica como se aplica a otras EventBus implementaciones así, que tienes que limpiar los recursos.
Sin embargo, usted puede hacer su vida más fácil para aquellos casos. Por ejemplo, usted podría mono parche $rootScope
y darle un $onRootScope
que se adhiere a los eventos emitidos en el $rootScope
pero también directamente limpia el controlador cuando el local $scope
se destruye.
La forma más limpia de monkey parche de la $rootScope
a proporcionar dicha $onRootScope
método sería a través de un decorador (a ejecutar el bloque probablemente hará bien así, pero pssst, no digas a nadie)
Para asegurarse de que el $onRootScope
de la propiedad no se muestra inesperado, cuando la enumeración sobre $scope
usamos Object.defineProperty()
y establezca enumerable
a false
. Tenga en cuenta que usted puede ser que necesite un ES5 calza.
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;
}]);
}]);
Con este método el código de controlador de arriba se puede simplificar a:
angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);
Así como un resultado final de todo esto me es altamente recomendable utilizar $rootScope.$emit
+ $scope.$onRootScope
.
Por cierto, estoy tratando de convencer a los angular equipo para abordar el problema dentro angular del núcleo. Hay una discusión aquí: https://github.com/angular/angular.js/issues/4574
Aquí es un jsperf que muestra la cantidad de un perf impacto $broadcast
trae a la mesa en un digno escenario con apenas 100 $scope
s'.
http://jsperf.com/rootscope-emit-vs-rootscope-broadcast