Sunting : Masalah yang dibahas dalam jawaban ini telah diatasi dalam angular.js versi 1.2.7 . $broadcast
sekarang hindari menggelegak atas cakupan yang tidak terdaftar dan berjalan secepat $ emit.
Jadi, sekarang Anda dapat:
- gunakan
$broadcast
dari$rootScope
- dengarkan menggunakan
$on
dari lokal$scope
yang perlu tahu tentang acara tersebut
Jawaban Asli Di Bawah Ini
Saya sangat menyarankan untuk tidak menggunakan $rootScope.$broadcast
+ $scope.$on
melainkan $rootScope.$emit
+ $rootScope.$on
. Yang pertama dapat menyebabkan masalah kinerja serius seperti yang diangkat oleh @numan. Itu karena acara tersebut akan menyebar melalui semua ruang lingkup.
Namun, yang terakhir (menggunakan $rootScope.$emit
+ $rootScope.$on
) tidak menderita ini dan karena itu dapat digunakan sebagai saluran komunikasi yang cepat!
Dari dokumentasi sudut $emit
:
Mengirim nama acara ke atas melalui hierarki lingkup yang memberitahukan yang terdaftar
Karena tidak ada ruang lingkup di atas $rootScope
, tidak ada gelembung yang terjadi. Sangat aman untuk menggunakan $rootScope.$emit()
/ $rootScope.$on()
sebagai EventBus.
Namun, ada satu gotcha saat menggunakannya dari dalam Controllers. Jika Anda langsung mengikat $rootScope.$on()
dari dalam controller, Anda harus membersihkan sendiri mengikat ketika lokal Anda $scope
hancur. Ini karena pengontrol (berbeda dengan layanan) dapat dipakai berkali-kali selama masa aplikasi yang akan menghasilkan binding yang akhirnya membuat kebocoran memori di semua tempat :)
Untuk unregister, hanya mendengarkan pada Anda $scope
's $destroy
acara dan kemudian memanggil fungsi yang dikembalikan oleh $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);
}
]);
Saya akan mengatakan, itu bukan hal yang sangat spesifik karena berlaku untuk implementasi EventBus lain juga, bahwa Anda harus membersihkan sumber daya.
Namun, Anda dapat membuat hidup Anda lebih mudah untuk kasus-kasus itu. Misalnya, Anda dapat menambal monyet $rootScope
dan memberikannya $onRootScope
yang berlangganan acara yang dipancarkan di $rootScope
tetapi juga secara langsung membersihkan pawang ketika lokal $scope
dihancurkan.
Cara paling bersih untuk menambal monyet $rootScope
untuk memberikan $onRootScope
metode seperti itu akan melalui dekorator (blok run mungkin akan melakukannya dengan baik juga tapi pssst, jangan bilang siapa-siapa)
Untuk memastikan $onRootScope
properti tidak muncul secara tak terduga saat menghitung lebih dari, $scope
kami menggunakan Object.defineProperty()
dan mengatur enumerable
untuk false
. Perlu diingat bahwa Anda mungkin memerlukan shim 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;
}]);
}]);
Dengan metode ini, kode pengontrol dari atas dapat disederhanakan menjadi:
angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);
Jadi sebagai hasil akhir dari semua ini saya sangat menyarankan Anda untuk menggunakan $rootScope.$emit
+ $scope.$onRootScope
.
Btw, saya mencoba meyakinkan tim sudut untuk mengatasi masalah dalam inti sudut. Ada diskusi yang terjadi di sini: https://github.com/angular/angular.js/issues/4574
Berikut adalah jsperf yang menunjukkan berapa banyak dampak perf yang $broadcast
dibawa ke meja dalam skenario yang layak hanya dengan 100 $scope
's.
http://jsperf.com/rootscope-emit-vs-rootscope-broadcast