我们有一个大型的Angularjs 1.6应用程序,它将$ rootscope分散在整个应用程序中,分布在过滤器,服务,路由等200多个地方。所以它需要重构,但我不知道怎么知道什么时候到去掉它。何时在应用程序中使用$ rootscope是最佳做法?
我已经从永远读过所有东西,用它来存储变量,我假设它是用于在控制器之间共享数据。我已经读过,最好将工厂/服务用于此用例,我还读到一个有效的用例是使用$ rootscope作为全局事件总线。
我没有在Angularjs文档中看到过这个解释。
答案 0 :(得分:9)
来自ng-book:
当Angular开始运行并生成视图时,它将从根ng-app创建绑定 元素到$ rootScope。这个$ rootScope是所有$ scope对象的最终父对象。 $ rootScope对象是我们对一个全局上下文中最近的对象 角度应用。将太多的逻辑附加到这个全球背景中是一个坏主意 同样地,弄脏JavaScript全局范围也不是一个好主意。
你是对的,你绝对应该使用服务在你的模块之间共享数据和逻辑。
在 $ rootScope 中加入大量逻辑意味着在您的应用程序中具有较差的可维护性和模块性,测试问题也非常困难。
我强烈建议你看看:
我知道将所有内容附加到 $ rootScope 可能很容易,但是很难处理它,进行少量更改,将代码重用于其他应用程序或模块并测试您的应用程序一般
修改强>
最近,我不得不从API获取一些项目并捕获这些项目,以便在某个视图中显示它们。项目提取机制位于某个Factory
,而格式化和显示项目的机制位于Controller
。
因此,我必须在获取项目时在Factory
中发出一个事件,并在Controller
中捕获此事件。
$ rootScope方式
//Factory
$rootScope.$broadcast('refreshItems', items);
//Controller
$scope.$on('refreshItems', doSomething());
它显然有用,但我并不真的喜欢使用$rootScope
,而且我也注意到这项任务的表现非常糟糕。
然后我尝试了一下Postal.js:
Postal.js是一条内存中的消息总线 - 受到AMQP的极大启发 - 用JavaScript编写。 Postal.js在浏览器或服务器上运行 使用node.js.这需要熟悉的" eventing-style"范式(of 大多数JavaScript开发人员都熟悉并扩展它 提供"经纪人"以及更多的订户实施 比通常在简单事件中找到的更复杂 发射/聚集。
我尝试使用Postal.js
来满足这种需求,我发现它实际上比使用$rootScope
更快。
//Factory
$scope.$bus.publish({
channel : 'reloadItems',
topic : 'reloadItems'
data : items
);
//Controller
$scope.$bus.subscribe({
channel : 'reloadItems',
topic : 'reloadItems',
callback : function () {
resetAndLoadItems();
}
});
我希望我能提供帮助。
答案 1 :(得分:3)
来自Angluar docs:每个应用程序都有一个根作用域。所有其他范围都是根范围的后代范围。 范围通过一种观察模型变化的机制,提供模型和视图之间的分离 。
当然,这将归结为意见和风格问题。我倾向于遵循非常接近John Papa's Angular Style Guide的风格。
为了与这两者保持一致,并且遵循良好的关注点分离策略,我的架构包含在整个应用程序中共享的工厂模型。反过来,我的控制器都绑定到保存共享数据的服务。
使用$ rootScope作为全局事件总线正是Angular使用它的方式。你应该标记并做同样的事情吗?我不明白为什么不。但如果您是,请确保目的明确定义,甚至可以使用您自己的服务将事件注册到全局事件总线。这样您就可以将应用程序与Angular分离,如果您决定要更改全局事件总线所在的框架,则可以在一个位置更改它。
这就是我的建议:
全球活动巴士
// Angular specific: add service to module
angular.module('app').factory('globalEventBus', GlobalEventBus);
// Angular specific: inject dependencies
GlobalEventBus.$inject(['$rootScope']);
// Non framework specific.
// param: fameworkEventBus will be $rootScope once injected
function GlobalEventBus(fameworkEventBus) {
var globalEventBus = this;
globalEventBus.registerEvent(params...){
fameworkEventBus.
}
return globalEventBus;
}
全球数据模型
我的数据模型很智能,往往包含提供自身信息或检索/返回特定数据的函数。
// Angular specific: add service to module
angular.module('app').factory('dataModel', DataModel);
function DataModel() {
var dataModel= this;
dataModel.myData = {};
dataModel.GetSpecificData = funtion(param){
return ...
}
return dataModel;
}
控制器
// Angular specific
angular.module('app').controller('MyController', MyController);
// Angular specific: inject dependencies to controller
MyController.$inject = ['dataModel'];
// By convention I use the same parameter name as the service.
// It helps me see quickly if my order of injection is correct
function MyController(dataModel) {
var myController = this;
// Bind to the service itself, and NOT to the service data property
myController.myData = dataModel;
myController.doStuff = function(){
}
}
Here是关于绑定服务而不是服务属性的有趣帖子。
总而言之,你必须成为最适合你的人的判断。良好的系统架构和良好的风格为我节省了无数个小时,解决了完全可以避免的问题。
答案 2 :(得分:0)
在使用Angular做更多的工作并且阅读更多之后,我找到了使用$ rootscope的基本经验法则,我希望将其添加到其他答案中:
仅添加静态或常量属性。还有别的 代表一个变化的状态或一个可变的值应该有一个 相应的指令或控制器来处理它。