$ rootScope。$ broadcast vs. $ scope。$ emit

本文探讨了AngularJS中$broadcast和$emit在事件传递方向、范围及使用场景上的区别。$emit沿作用域层级向上派发事件,而$broadcast则向下派发至所有子作用域。文章还讨论了它们的效率问题,提出了Pub/Sub模式作为更高效的替代方案。
部署运行你感兴趣的模型镜像

本文翻译自:$rootScope.$broadcast vs. $scope.$emit

Now that the performance difference between $broadcast and $emit has been eliminated, is there any reason to prefer $scope.$emit to $rootScope.$broadcast ? 现在已经消除了$broadcast$emit之间的性能差异,是否有任何理由更喜欢$scope.$emit to $rootScope.$broadcast

They are different, yes. 他们是不同的,是的。

$emit is restricted to the scope hierarchy (upwards) - this may be good, if it fits your design, but it seems to me a rather arbitrary restriction. $emit仅限于范围层次结构(向上) - 如果它符合您的设计,这可能是好的,但在我看来这是一个相当随意的限制。

$rootScope.$broadcast works across all that choose to listen to the event, which is a more sensible restriction in my mind. $rootScope.$broadcast适用于所有选择收听事件的人,这在我看来是一个更明智的限制。

Am I missing something? 我错过了什么吗?

EDIT: 编辑:

To clarify in response to an answer, the direction of the dispatch is not the issue I'm after. 为了澄清答案,发送的方向不是我追求的问题。 $scope.$emit dispatches the event upwards, and $scope.$broadcast - downwards. $scope.$emit向上调度事件, $scope.$broadcast - 向下调度。 But why not always use $rootScope.$broadcast to reach all the intended listeners? 但为什么不总是使用$rootScope.$broadcast来覆盖所有预期的听众呢?


#1楼

参考:https://stackoom.com/question/1oFQM/rootScope-broadcast-vs-scope-emit


#2楼

他们没有做同样的工作: $emit通过范围层次结构向上调度事件,而$broadcast将事件向下调度到所有子范围。


#3楼

tl;dr (this tl;dr is from @sp00m 's answer below) tl; dr (这个tl;博士来自@ sp00m的答案)

$emit dispatches an event upwards ... $broadcast dispatches an event downwards $emit向上调度一个事件... $broadcast向下调度一个事件

Detailed explanation 详细解释

$rootScope.$emit only lets other $rootScope listeners catch it. $rootScope.$emit只允许其他$rootScope侦听器捕获它。 This is good when you don't want every $scope to get it. 当你不希望每个$scope获得它时,这很好。 Mostly a high level communication. 主要是高级别的沟通。 Think of it as adults talking to each other in a room so the kids can't hear them. 可以把它想象成成年人在一个房间里互相交谈,这样孩子们就听不到了。

$rootScope.$broadcast is a method that lets pretty much everything hear it. $rootScope.$broadcast是一种几乎可以听到它的方法。 This would be the equivalent of parents yelling that dinner is ready so everyone in the house hears it. 这相当于父母大喊大叫,晚餐准备就绪,所以房子里的每个人都听到了。

$scope.$emit is when you want that $scope and all its parents and $rootScope to hear the event. $scope.$emit是你希望$scope及其所有父项和$rootScope听到事件的时间。 This is a child whining to their parents at home (but not at a grocery store where other kids can hear). 这是一个在家里向父母抱怨的孩子(但不是在其他孩子可以听到的杂货店)。

$scope.$broadcast is for the $scope itself and its children. $scope.$broadcast用于$scope本身及其子节点。 This is a child whispering to its stuffed animals so their parents can't hear. 这是一个孩子对它的毛绒动物窃窃私语,所以他们的父母听不到。


#4楼

@Eddie has given a perfect answer of the question asked. @Eddie给出了问题的完美答案。 But I would like to draw attention to using an more efficient approach of Pub/Sub. 但我想提请注意使用更有效的Pub / Sub方法。

As this answer suggests, 正如这个答案所示,

The $broadcast/$on approach is not terribly efficient as it broadcasts to all the scopes(Either in one direction or both direction of Scope hierarchy). $ broadcast / $ on方法不是非常有效,因为它广播到所有范围(在Scope层次结构的一个方向或两个方向上)。 While the Pub/Sub approach is much more direct. 而Pub / Sub方法更直接。 Only subscribers get the events, so it isn't going to every scope in the system to make it work. 只有订阅者才能获得事件,因此不会让系统中的每个范围都能使其生效。

you can use angular-PubSub angular module. 你可以使用angular-PubSub角度模块。 once you add PubSub module to your app dependency, you can use PubSub service to subscribe and unsubscribe events/topics. PubSub模块添加到app依赖项后,您可以使用PubSub服务订阅和取消订阅事件/主题。

Easy to subscribe: 易于订阅:

// Subscribe to event
var sub = PubSub.subscribe('event-name', function(topic, data){

});

Easy to publish 易于发布

PubSub.publish('event-name', {
    prop1: value1,
    prop2: value2
});

To unsubscribe, use PubSub.unsubscribe(sub); 要取消订阅,请使用PubSub.unsubscribe(sub); OR PubSub.unsubscribe('event-name'); PubSub.unsubscribe('event-name'); .

NOTE Don't forget to unsubscribe to avoid memory leaks. 注意不要忘记取消订阅以避免内存泄漏。


#5楼

I made the following graphic out of the following link: https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/ 我通过以下链接制作了以下图片: https//toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

范围,rootScope,发射,广播

As you can see, $rootScope.$broadcast hits a lot more listeners than $scope.$emit . 正如你所看到的, $rootScope.$broadcast$scope.$emit更多听众$scope.$emit

Also, $scope.$emit 's bubbling effect can be cancelled, whereas $rootScope.$broadcast cannot. 另外, $scope.$emit的冒泡效果可以取消,而$rootScope.$broadcast则不能。


#6楼

Use RxJS in a Service 在服务中使用RxJS

What about in a situation where you have a Service that's holding state for example. 例如,在您拥有一个处于保持状态的服务的情况下。 How could I push changes to that Service, and other random components on the page be aware of such a change? 如何将更改推送到该服务,页面上的其他随机组件是否知道这种更改? Been struggling with tackling this problem lately 最近一直在努力解决这个问题

Build a service with RxJS Extensions for Angular . 使用RxJS Extensions for Angular构建服务。

<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/rx/dist/rx.all.js"></script>
<script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>
var app = angular.module('myApp', ['rx']);

app.factory("DataService", function(rx) {
  var subject = new rx.Subject(); 
  var data = "Initial";

  return {
      set: function set(d){
        data = d;
        subject.onNext(d);
      },
      get: function get() {
        return data;
      },
      subscribe: function (o) {
         return subject.subscribe(o);
      }
  };
});

Then simply subscribe to the changes. 然后只需订阅更改。

app.controller('displayCtrl', function(DataService) {
  var $ctrl = this;

  $ctrl.data = DataService.get();
  var subscription = DataService.subscribe(function onNext(d) {
      $ctrl.data = d;
  });

  this.$onDestroy = function() {
      subscription.dispose();
  };
});

Clients can subscribe to changes with DataService.subscribe and producers can push changes with DataService.set . 客户端可以使用DataService.subscribe订阅更改,生产者可以使用DataService.set推送更改。

The DEMO on PLNKR . PLNKR上DEMO

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们注意到用户本次询问的是AngularJS中的$scope概念(注意是AngularJS,不是Angular)。根据引用内容,$scopeAngularJS中扮演着核心角色,它是连接控制器(Controller)和视图(View)的桥梁,也是实现双向数据绑定的基础。下面将结合引用内容详细说明。###1.$scope的作用-**数据绑定载体**:$scope是一个JavaScript对象,用于存储视图所需的数据模型。在HTML中通过`{{表达式}}`或指令绑定$scope的属性[^1][^2]。-**作用域继承**:$scope形成树形结构,子$scope(如嵌套控制器内)会原型继承父$scope的属性(除非子$scope重写属性)[^1][^3]。-**事件传播**:提供`$emit()`向上(父级)和`$broadcast()`向下(子级)传播事件的方法[^1][^4]。-**变更检测**:通过`$watch()`监听数据变化,`$apply()`触发脏检查更新视图[^1][^4]。###2.$scope的生命周期(引用[4])1.**创建**:当控制器或指令被实例化时创建2.**注册监控**:模板中的绑定会自动注册`$watch`3.**模型变更**:用户交互或服务调用导致数据变化4.**变更观察**:AngularJS的脏检查机制检测变化5.**销毁**:当$scope不再需要时(如路由切换),调用`$destroy()`清理资源###3.关键使用场景####a)控制器中定义模型数据```javascriptmyApp.controller('firstCtrl',['$scope',function($sc){$sc.name="张三丰";//视图可通过{{name}}访问}]);```####b)嵌套作用域继承(引用[2]示例)```html<divng-controller="parentCtrl">{{name}}<!--显示父级name--><divng-controller="childCtrl">{{name}}<!--显示子级name,覆盖父级属性-->{{age}}<!--继承自父级--></div></div>```####c)根作用域($rootScope)-整个应用唯一的顶级作用域,通过依赖注入使用[^2]:```javascriptmyApp.run(['$rootScope',function($rsc){$rsc.sex='男';//全局可访问}]);```####d)事件通信```javascript//子控制器发送事件$scope.$emit('userEvent',data);//父控制器监听$scope.$on('userEvent',function(event,data){...});```###4.注意事项-**作用域隔离**:指令中使用`scope:{...}`会创建独立作用域,不继承父级属性[^3]-**性能优化**:避免过度使用`$watch`,及时移除手动注册的监听器-**避免直接操作DOM**:数据变更应通过$scope,由AngularJS更新视图###示例代码解析(引用[2])```html<!--视图--><divng-app="myApp"><divng-controller="firstCtrl">{{name}}<!--"张三丰"-->{{age}}<!--未定义,不显示--><divng-controller="secondCtrl">{{name}}<!--"灭绝师太"(覆盖父级)-->{{age}}<!--108(来自$rootScope)-->{{sex}}<!--"男"(来自$rootScope)--></div></div>{{sex}}<!--"男"(全局)--></div><script>varmyApp=angular.module('myApp',[]);//控制器1:注入$scopemyApp.controller('firstCtrl',['$scope',function($sc){$sc.name="张三丰";}]);//控制器2:同时注入$scope$rootScopemyApp.controller('secondCtrl',['$scope','$rootScope',function($sc,$rsc){$sc.name="灭绝师太";$rsc.age=108;//直接修改$rootScope}]);//初始化全局数据myApp.run(['$rootScope',function($rsc){$rsc.sex='男';}]);</script>```**效果解释**:-`firstCtrl`作用域:只有`name`属性-`secondCtrl`作用域:有`name`属性(覆盖父级),通过`$rootScope`设置`age`全局可见-`sex`由`$rootScope`定义,所有作用域可访问§§相关问题§§1.AngularJS中如何实现控制器之间的通信?2.$scope.$watch()的使用场景和注意事项是什么?3.AngularJS与Angular在作用域管理上有何区别?</think>### AngularJS$scope的作用与使用方法 **$scope** 是 AngularJS(1.x)的核心概念,作为连接控制器(Controller)和视图(View)的桥梁,实现**双向数据绑定**和**MVC架构**的基础[^1][^4]。以下是详细解析: --- ### 一、核心作用 1. **数据模型载体** - 存储视图所需数据,如`$scope.name = "张三丰"`[^2] - 在HTML中通过`{{name}}`直接访问[^2] 2. **作用域继承体系** - 树形结构:从根作用域`$rootScope`(ng-app层级)向下继承[^1][^3] - 子作用域**原型继承**父作用域属性(非覆盖式继承)[^3] ```html <!-- 示例:嵌套作用域 --> <div ng-controller="parentCtrl"> {{name}} <!-- 父级数据 --> <div ng-controller="childCtrl"> {{name}} <!-- 可访问父级name,除非重写 --> </div> </div> ``` 3. **事件传播机制** - `$scope.$emit()`:向上传递事件(父级/祖先)[^1] - `$scope.$broadcast()`:向下传递事件(子级/后代)[^1] 4. **变更检测基础** - `$scope.$watch()`:监听数据变化[^1][^4] - `$scope.$apply()`:手动触发脏检查(更新视图)[^4] --- ### 二、关键使用方法 #### 1. 基础数据绑定 ```javascript myApp.controller('demoCtrl', ['$scope', function($scope) { $scope.title = "Hello AngularJS"; // 定义模型数据 $scope.user = { id: 1, name: "John" }; }]); ``` ```html <!-- 视图绑定 --> <h1>{{title}}</h1> <p>User: {{user.name}}</p> ``` #### 2. 作用域继承实践 ```javascript // 父控制器 myApp.controller('parentCtrl', ['$scope', function($scope) { $scope.sharedData = "父级数据"; }]); // 子控制器 myApp.controller('childCtrl', ['$scope', function($scope) { // 自动继承sharedData,可直接使用 $scope.localData = "子级独有数据"; // 仅子作用域可见 }]); ``` #### 3. 事件通信 ```javascript // 子控制器发送事件 $scope.$emit('customEvent', { data: "向上传递" }); // 父控制器监听事件 $scope.$on('customEvent', function(event, args) { console.log("收到事件:", args.data); // 输出"向上传递" }); ``` #### 4. 监听数据变化 ```javascript $scope.$watch('user.name', function(newVal, oldVal) { console.log(`名字从 ${oldVal} 变为 ${newVal}`); }); ``` --- ### 三、重要注意事项 1. **作用域隔离性** - 每个`ng-controller`创建独立$scope[^3] - 指令(如`ng-repeat`)会创建子作用域 2. **根作用域($rootScope)** - 全局唯一顶级作用域[^1][^4] - 存储全局数据(如用户登录状态) ```javascript myApp.run(['$rootScope', function($rootScope) { $rootScope.appVersion = "1.0.0"; }]); ``` 3. **性能优化** - 避免深层嵌套`$watch`(影响脏检查效率) - 及时销毁作用域:`$scope.$destroy()`[^4] --- ### 典型问题示例 ```html <div ng-app="myApp"> <div ng-controller="mainCtrl"> {{globalData}} <!-- 显示根作用域数据 --> <div ng-controller="subCtrl"> {{localData}} <!-- 子作用域数据 --> {{globalData}} <!-- 仍可访问根作用域 --> </div> </div> </div> <script> angular.module('myApp', []) .run(['$rootScope', function(rs) { rs.globalData = "根作用域数据"; }]) .controller('mainCtrl', ['$scope', function($scope) { $scope.mainProp = "主控制器属性"; }]) .controller('subCtrl', ['$scope', function($scope) { $scope.localData = "子控制器数据"; }]); </script> ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值