Chỉnh sửa : Vấn đề được giải quyết trong câu trả lời này đã được giải quyết trong phiên bản angular.js 1.2.7 . $broadcast
bây giờ tránh sủi bọt trên phạm vi chưa đăng ký và chạy nhanh như $ phát ra.
Vì vậy, bây giờ bạn có thể:
- sử dụng
$broadcast
từ$rootScope
- lắng nghe bằng cách sử dụng
$on
từ địa phương$scope
cần biết về sự kiện này
Câu trả lời gốc bên dưới
Tôi khuyên bạn không nên sử dụng $rootScope.$broadcast
+ $scope.$on
mà là $rootScope.$emit
+ $rootScope.$on
. Cái trước có thể gây ra vấn đề hiệu suất nghiêm trọng như được nêu ra bởi @numan. Đó là bởi vì sự kiện sẽ bong bóng xuống qua tất cả các phạm vi.
Tuy nhiên, cái sau (sử dụng $rootScope.$emit
+ $rootScope.$on
) không bị như vậy và do đó có thể được sử dụng như một kênh liên lạc nhanh!
Từ các tài liệu góc của $emit
:
Gửi một tên sự kiện trở lên thông qua hệ thống phân cấp phạm vi thông báo đã đăng ký
Vì không có phạm vi ở trên $rootScope
, không có bong bóng xảy ra. Hoàn toàn an toàn khi sử dụng $rootScope.$emit()
/ $rootScope.$on()
làm EventBus.
Tuy nhiên, có một gotcha khi sử dụng nó từ bên trong Bộ điều khiển. Nếu bạn liên kết trực tiếp $rootScope.$on()
từ bên trong bộ điều khiển, bạn sẽ phải tự dọn sạch ràng buộc khi địa phương của bạn $scope
bị phá hủy. Điều này là do các bộ điều khiển (trái ngược với các dịch vụ) có thể được khởi tạo nhiều lần trong suốt vòng đời của một ứng dụng dẫn đến các ràng buộc tóm tắt cuối cùng tạo ra rò rỉ bộ nhớ ở mọi nơi :)
Để unregister, chỉ cần lắng nghe trên của bạn $scope
's $destroy
sự kiện và sau đó gọi hàm đã được trả về bởi $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);
}
]);
Tôi có thể nói, đó thực sự không phải là một điều cụ thể góc cạnh vì nó cũng áp dụng cho các triển khai EventBus khác, rằng bạn phải dọn sạch các tài nguyên.
Tuy nhiên, bạn có thể làm cho cuộc sống của bạn dễ dàng hơn cho những trường hợp đó. Chẳng hạn, bạn có thể vá khỉ $rootScope
và cho nó $onRootScope
đăng ký các sự kiện phát ra trên $rootScope
nhưng cũng trực tiếp dọn sạch trình xử lý khi cục bộ $scope
bị phá hủy.
Cách sạch nhất để khỉ vá phương pháp $rootScope
cung cấp $onRootScope
phương pháp như vậy là thông qua một người trang trí (một khối chạy có thể sẽ làm tốt như vậy nhưng pssst, đừng nói với ai)
Để đảm bảo $onRootScope
tài sản không xuất hiện bất ngờ khi liệt kê $scope
chúng tôi sử dụng Object.defineProperty()
và đặt enumerable
thành false
. Hãy nhớ rằng bạn có thể cần một 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;
}]);
}]);
Với phương pháp này, mã điều khiển từ trên có thể được đơn giản hóa thành:
angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);
Vì vậy, như là kết quả cuối cùng của tất cả điều này, tôi khuyên bạn nên sử dụng $rootScope.$emit
+ $scope.$onRootScope
.
Btw, tôi đang cố gắng thuyết phục đội ngũ góc cạnh để giải quyết vấn đề trong lõi góc. Có một cuộc thảo luận đang diễn ra ở đây: https://github.com/angular/angular.js/issues/4574
Dưới đây là một jsperf cho thấy mức độ ảnh hưởng hoàn hảo $broadcast
mang đến cho bảng trong một kịch bản hợp lý chỉ với 100 $scope
giây.
http://jsperf.com/rootscope-emit-vs-rootscope-broadcast