Bearbeiten : Das in dieser Antwort angesprochene Problem wurde in angle.js Version 1.2.7 behoben . $broadcast
Jetzt wird das Sprudeln über nicht registrierte Bereiche vermieden und läuft genauso schnell wie $ emit.
So, jetzt können Sie:
- Verwendung
$broadcast
aus dem$rootScope
- Hören Sie mit
$on
dem lokalen$scope
, der über das Ereignis wissen muss
Originalantwort unten
Ich rate dringend, nicht $rootScope.$broadcast
+ $scope.$on
, sondern $rootScope.$emit
+ zu verwenden $rootScope.$on
. Ersteres kann schwerwiegende Leistungsprobleme verursachen, wie von @numan angesprochen. Das liegt daran, dass das Ereignis durch alle Bereiche sprudelt .
Letzteres (mit $rootScope.$emit
+ $rootScope.$on
) leidet jedoch nicht darunter und kann daher als schneller Kommunikationskanal verwendet werden!
Aus der Winkeldokumentation von $emit
:
Versendet einen Ereignisnamen über die Bereichshierarchie nach oben und benachrichtigt den Registrierten
Da oben kein Bereich $rootScope
vorhanden ist, tritt kein Sprudeln auf. Es ist absolut sicher, $rootScope.$emit()
/ $rootScope.$on()
als EventBus zu verwenden.
Es gibt jedoch ein Problem, wenn Sie es in Controllern verwenden. Wenn Sie direkt $rootScope.$on()
von einem Controller aus eine Bindung herstellen, müssen Sie die Bindung selbst bereinigen, wenn Ihr lokaler $scope
Server zerstört wird. Dies liegt daran, dass Controller (im Gegensatz zu Diensten) über die Lebensdauer einer Anwendung mehrmals instanziiert werden können, was dazu führen würde, dass Bindungen summiert werden und überall Speicherlecks entstehen :)
Um austragen, hört nur auf $scope
‚s $destroy
Ereignis und dann die Funktion aufrufen , die von zurückgegeben wurde $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);
}
]);
Ich würde sagen, das ist nicht wirklich eine eckenspezifische Sache, da es auch für andere EventBus-Implementierungen gilt, dass Sie Ressourcen bereinigen müssen.
In diesen Fällen können Sie Ihnen jedoch das Leben erleichtern. Zum Beispiel könnten Sie einen Affen-Patch erstellen $rootScope
und ihm einen geben $onRootScope
, der Ereignisse abonniert, die auf dem $rootScope
ausgegeben werden, aber auch den Handler direkt bereinigt, wenn der lokale $scope
Server zerstört wird.
Der sauberste Weg, um Affen zu patchen $rootScope
, um eine solche $onRootScope
Methode bereitzustellen , wäre durch einen Dekorateur (ein Run-Block wird es wahrscheinlich auch gut machen, aber pssst, sag es niemandem)
Um sicherzustellen, dass die $onRootScope
Eigenschaft beim Aufzählen nicht unerwartet angezeigt wird, verwenden $scope
wir Object.defineProperty()
und setzen enumerable
auf false
. Denken Sie daran, dass Sie möglicherweise eine ES5-Unterlegscheibe benötigen.
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;
}]);
}]);
Mit dieser Methode kann der Controller-Code von oben vereinfacht werden, um:
angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);
Als Endergebnis all dessen rate ich Ihnen dringend, $rootScope.$emit
+ zu verwenden $scope.$onRootScope
.
Übrigens versuche ich, das Winkel-Team davon zu überzeugen, das Problem innerhalb des Winkelkerns anzugehen. Hier findet eine Diskussion statt: https://github.com/angular/angular.js/issues/4574
Hier ist ein jsperf, das zeigt, wie viel Perfektion $broadcast
in einem anständigen Szenario mit nur 100 Sekunden auf den Tisch kommt $scope
.
http://jsperf.com/rootscope-emit-vs-rootscope-broadcast