Edit : Le problème abordé dans cette réponse a été résolu dans angular.js version 1.2.7 . $broadcast
évite désormais de se propager sur des étendues non enregistrées et s'exécute aussi vite que $ emit.
Vous pouvez donc désormais:
- utiliser à
$broadcast
partir du$rootScope
- écouter en utilisant
$on
le local$scope
qui a besoin de connaître l'événement
Réponse originale ci-dessous
Je conseille fortement de ne pas utiliser $rootScope.$broadcast
+ $scope.$on
mais plutôt $rootScope.$emit
+ $rootScope.$on
. Le premier peut entraîner de graves problèmes de performances, comme l'a soulevé @numan. En effet, l'événement bouillonnera dans tous les domaines.
Cependant, ce dernier (en utilisant $rootScope.$emit
+ $rootScope.$on
) n'en souffre pas et peut donc être utilisé comme canal de communication rapide!
De la documentation angulaire de $emit
:
Distribue un nom d'événement vers le haut à travers la hiérarchie d'étendue notifiant les inscrits
Puisqu'il n'y a pas de portée ci $rootScope
- dessus , il n'y a pas de bouillonnement. Il est totalement sûr d'utiliser $rootScope.$emit()
/ $rootScope.$on()
comme EventBus.
Cependant, il existe un problème lors de son utilisation à partir de contrôleurs. Si vous vous connectez directement à $rootScope.$on()
partir d'un contrôleur, vous devrez nettoyer la liaison vous-même lorsque votre section locale sera $scope
détruite. En effet, les contrôleurs (contrairement aux services) peuvent être instanciés plusieurs fois au cours de la durée de vie d'une application, ce qui entraînerait la synthèse des liaisons, créant éventuellement des fuites de mémoire partout :)
Pour annuler l' enregistrement, il suffit d' écouter sur votre $scope
de » $destroy
l'événement, puis appeler la fonction qui a été renvoyée par $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);
}
]);
Je dirais que ce n'est pas vraiment une chose spécifique angulaire, car cela s'applique également aux autres implémentations EventBus, que vous devez nettoyer les ressources.
Cependant, vous pouvez vous faciliter la vie dans ces cas. Par exemple, vous pouvez corriger le singe $rootScope
et lui donner un $onRootScope
qui s'abonne aux événements émis sur le $rootScope
mais nettoie également directement le gestionnaire lorsque le local $scope
est détruit.
La façon la plus propre de patcher le singe $rootScope
pour fournir une telle $onRootScope
méthode serait de passer par un décorateur (un bloc d'exécution le fera probablement très bien aussi mais pssst, ne le dites à personne)
Pour vous assurer que la $onRootScope
propriété ne s'affiche pas de manière inattendue lors de l'énumération, $scope
nous utilisons Object.defineProperty()
et définissons enumerable
sur false
. Gardez à l'esprit que vous pourriez avoir besoin d'une cale 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;
}]);
}]);
Avec cette méthode en place, le code du contrôleur ci-dessus peut être simplifié pour:
angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);
Donc, comme résultat final de tout cela, je vous conseille fortement d'utiliser $rootScope.$emit
+ $scope.$onRootScope
.
Btw, j'essaie de convaincre l'équipe angulaire de résoudre le problème dans le noyau angulaire. Il y a une discussion en cours ici: https://github.com/angular/angular.js/issues/4574
Voici un jsperf qui montre combien un impact de perf $broadcast
apporte à la table dans un scénario décent avec seulement 100 $scope
.
http://jsperf.com/rootscope-emit-vs-rootscope-broadcast