แก้ไข : ปัญหาการแก้ไขในคำตอบนี้ได้รับการแก้ไขใน angular.js เวอร์ชัน 1.2.7 $broadcast
ตอนนี้หลีกเลี่ยงการเดือดดาลเหนือขอบเขตที่ไม่ได้ลงทะเบียนและทำงานได้เร็วเท่ากับ $ emit
ดังนั้นตอนนี้คุณสามารถ:
- ใช้
$broadcast
จาก$rootScope
- ฟังการใช้งาน
$on
จากท้องถิ่น$scope
ที่จำเป็นต้องรู้เกี่ยวกับเหตุการณ์
คำตอบเดิมด้านล่าง
ผมขอให้คำแนะนำที่จะไม่ใช้$rootScope.$broadcast
+ $scope.$on
แต่+$rootScope.$emit
$rootScope.$on
อดีตอาจทำให้เกิดปัญหาประสิทธิภาพการทำงานที่ร้ายแรงโดย @numan นั่นเป็นเพราะเหตุการณ์จะทำให้ฟองดูในขอบเขตทั้งหมด
อย่างไรก็ตามหลัง (ใช้$rootScope.$emit
+ $rootScope.$on
) ไม่ประสบกับสิ่งนี้และสามารถใช้เป็นช่องทางการสื่อสารที่รวดเร็ว!
จากเอกสารเชิงมุมของ$emit
:
ยื้อชื่อเหตุการณ์ขึ้นไปตามลำดับชั้นขอบเขตแจ้งการลงทะเบียน
เนื่องจากไม่มีขอบเขตด้านบน$rootScope
จึงไม่มีการเดือดปุด ๆ มีความปลอดภัยทั้งหมดที่จะใช้$rootScope.$emit()
/ $rootScope.$on()
เป็น EventBus
อย่างไรก็ตามมีหนึ่ง gotcha เมื่อใช้มันจากภายในตัวควบคุม ถ้าคุณผูกโดยตรง$rootScope.$on()
จากภายในตัวควบคุมคุณจะต้องทำความสะอาดตัวเองเมื่อท้องถิ่นของคุณ$scope
ถูกทำลาย นี่เป็นเพราะตัวควบคุม (ตรงกันข้ามกับบริการ) สามารถรับอินสแตนซ์ได้หลายครั้งตลอดอายุการใช้งานของแอปพลิเคชันซึ่งจะส่งผลให้เกิดการสรุปรวมในที่สุดการสร้างหน่วยความจำรั่วทั่วสถานที่ :)
ถอนการลงทะเบียนเพียงแค่ฟังคุณ$scope
's เหตุการณ์แล้วเรียกฟังก์ชั่นที่ถูกส่งกลับโดย$destroy
$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);
}
]);
ฉันจะบอกว่านั่นไม่ใช่สิ่งที่เฉพาะเจาะจงเชิงมุมเพราะมันใช้กับการใช้งาน EventBus อื่น ๆ เช่นกันว่าคุณต้องทำความสะอาดทรัพยากร
อย่างไรก็ตามคุณสามารถทำให้ชีวิตของคุณง่ายขึ้นสำหรับกรณีเหล่านั้น ตัวอย่างเช่นคุณสามารถแก้ไขลิง$rootScope
และให้มัน$onRootScope
ที่สมัครสมาชิกกับเหตุการณ์ที่ปล่อยออกมาใน$rootScope
แต่ยังทำความสะอาดตัวจัดการโดยตรงเมื่อท้องถิ่น$scope
ถูกทำลาย
วิธีที่สะอาดที่สุดในการติดตั้งลิง$rootScope
เพื่อให้$onRootScope
วิธีการดังกล่าวคือผ่านมัณฑนากร
เพื่อให้แน่ใจว่า$onRootScope
คุณสมบัติไม่ปรากฏขึ้นไม่คาดคิดเมื่อแจงมากกว่า$scope
ที่เราใช้Object.defineProperty()
และการตั้งค่าไปenumerable
false
โปรดทราบว่าคุณอาจต้องการ ES5 shim
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;
}]);
}]);
ด้วยวิธีนี้ในสถานที่รหัสควบคุมจากด้านบนสามารถง่ายต่อการ:
angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);
เพื่อให้เป็นผลสุดท้ายของทั้งหมดนี้ผมขอแนะนำให้คุณใช้+$rootScope.$emit
$scope.$onRootScope
Btw ฉันพยายามโน้มน้าวให้ทีมงานเชิงมุมเพื่อแก้ไขปัญหาภายในแกนเชิงมุม มีการสนทนาเกิดขึ้นที่นี่: https://github.com/angular/angular.js/issues/4574
นี่คือ jsperf ที่แสดงให้เห็นว่าผลกระทบที่สมบูรณ์แบบ$broadcast
นำมาสู่ตารางในสถานการณ์ที่ดีเพียง 100 $scope
เท่านั้น
http://jsperf.com/rootscope-emit-vs-rootscope-broadcast