为什么不建议将 $rootScope 与函数一起使用?
Why using $rootScope with functions is not recommended?
在查看 Angularjs 的 FEQ 时,我看到了以下文章:
$rootScope exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope
and set values on it like any other scope. Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like ng-show
just like values on your local $scope
.
Of course, global state sucks and you should use $rootScope
sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope
, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
— AngularJS FAQ - $rootScope exists, but it can be used for evil
所以我的疑问是为什么不建议将 $rootScope 作为全局函数用于函数?有没有性能问题?
全局变量被滥用
$rootScope
几乎是一个全局变量并且有它的位置,但肯定被大多数使用它的人滥用。这些是通常不应使用全局变量的原因。
Non-locality -- Source code is easiest to understand when the scope of its individual elements are limited. Global variables can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.
No Access Control or Constraint Checking -- A global variable can be get or set by any part of the program, and any rules regarding its use can be easily broken or forgotten. (In other words, get/set accessors are generally preferable over direct data access, and this is even more so for global data.) By extension, the lack of access control greatly hinders achieving security in situations where you may wish to run untrusted code (such as working with 3rd party plugins).
Implicit coupling -- A program with many global variables often has tight couplings between some of those variables, and couplings between variables and functions. Grouping coupled items into cohesive units usually leads to better programs.
Concurrency issues -- if globals can be accessed by multiple threads of execution, synchronization is necessary (and too-often neglected). When dynamically linking modules with globals, the composed system might not be thread-safe even if the two independent modules tested in dozens of different contexts were safe.
Namespace pollution -- Global names are available everywhere. You may unknowingly end up using a global when you think you are using a local (by misspelling or forgetting to declare the local) or vice versa. Also, if you ever have to link together modules that have the same global variable names, if you are lucky, you will get linking errors. If you are unlucky, the linker will simply treat all uses of the same name as the same object.
Memory allocation issues -- Some environments have memory allocation schemes that make allocation of globals tricky. This is especially true in languages where "constructors" have side-effects other than allocation (because, in that case, you can express unsafe situations where two globals mutually depend on one another). Also, when dynamically linking modules, it can be unclear whether different libraries have their own instances of globals or whether the globals are shared.
Testing and Confinement - source that utilizes globals is somewhat more difficult to test because one cannot readily set up a 'clean' environment between runs. More generally, source that utilizes global services of any sort (e.g. reading and writing files or databases) that aren't explicitly provided to that source is difficult to test for the same reason. For communicating systems, the ability to test system invariants may require running more than one 'copy' of a system simultaneously, which is greatly hindered by any use of shared services - including global memory - that are not provided for sharing as part of the test.
来源: http://c2.com/cgi/wiki?GlobalVariablesAreBad
在 Angular
中共享数据
在 Angular 中跨控制器共享数据时,您应该使用服务。使用自定义服务,您可以创建 getter 和 setter 方法。您将它注入到您需要它的控制器中,并可以在您的应用程序中使用它。
不存在性能问题。它实际上可以将您的性能提高 时间的一部分 ,因为您不需要依赖注入大量服务。
但它是设计的一个大问题。考虑一个大型应用程序,它有几十个视图、复杂的组件并绑定到一个众所周知的 API 数量(例如 Twitter、Flickr、Facebook、OAuth 等)。
您不会单独开发此应用程序。会出现以下问题:
命名空间
您在 Facebook API 上工作,其他人在 Twitter API 上工作。你们都认为对函数使用 $rootScope
是个好主意,并且都编写了 $rootScope.login
函数。在做 git merge
时你会如何解决这个问题?你需要命名空间,唉,你需要开发两个服务myFacebookAPI
,myTwitterAPI
然后可以实现相同的登录接口。(login(user,pw)
)。请注意,当您可以执行以下操作时,这使您能够抽象出您在控制器中处理的实际社交网络:
$scope.callAction = function (action) {
var service;
if ($scope.serviceSelected === 'fb') {
service = myFacebookAPI;
} else {
service = myTwitterAPI;
}
service[action]();
};
测试
在进行专业开发时,您会编写测试。 Angular 为您提供了对服务等进行自动化测试的工具,但您无法以同样舒适的方式测试分配给 $rootScope
的内容。
其他问题也会出现,但我想这应该足够你自己考虑了。
我过去已经回答过这个问题,但你问这些问题很好。
$rootScope exists, but it can be used for evil Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
非隔离作用域是分层的,但大多数开发人员应该使用具有隔离作用域的指令。 AngularJS 作用域的层级性质是 许多 应用程序中错误的来源。这是一个我喜欢称之为 scope bleeding 的问题,其中范围 属性 在 DOM 树中的某处被神奇地修改了,而你不知道为什么。
Angular 的 default 行为是针对固有范围的,这使得一个控制器很容易更新另一个控制器管理的内容,依此类推.这就是在源代码之间创建意大利面条式连接的方式。使得维护该代码变得非常困难。
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope and set values on it like any other scope.
不,那是不正确的。 AngularJS 允许你定义诸如常量、值和服务之类的东西。这些东西可以注入到路由、控制器和指令中。这就是你如何让你的应用程序全局访问的东西,如果你想让你的控制器或指令可测试,你也可以这样做。单元测试编写者不知道指令或控制器所依赖的 $rootScope 中应该有哪些属性。他们必须假设 $rootScope 没有变异来提供服务或数据。
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language.
问题不是 $rootScope,而是人们用它做什么。许多应用程序将当前用户、身份验证令牌和会话数据添加到 rootScope 中。这最终会在模板中大量使用(如果用户登录则显示 X,否则显示 Y)。问题是 HTML 不传达范围层次结构。所以当你看到 {{user.firstname + ' ' + user.lastname}}
时,你不知道变量 user
是从哪里来的。第二个问题是子作用域可以隐藏根属性。与前面的示例一样,如果指令执行此操作 scope.user = 'bla bla bla'
。它没有替换 rootScope 上的值。它隐藏了它。现在你在模板中得到了一些奇怪的意想不到的东西,你不知道为什么变量 user
发生了变化。
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
Angular 的 $cacheFactory
和 $templateCache
是仅存储数据的服务示例。我认为作者试图鼓励在 Angular 的模块中使用常量和值,但这并不是一个好的描述。
So My doubt is why $rootScope is not recommended for functions as a global function? Is there any performance issue?
$rootScope 是 angular.config(..)
期间唯一可用的范围。如果这是唯一的时间,则可以在此期间修改范围。例如;您可能需要在 应用程序启动之前 注入 API 密钥或 Google 分析变量。
any 作用域上的函数通常不是一个好主意。主要是因为作用域中的所有内容都在模板的表达式中被消化。函数倾向于隐藏 繁重的操作。在调用函数时,通过读取 HTML 无法判断模板的重量。我见过像 getHeight()
这样的范围函数,其中函数本身执行 3 级嵌套循环。每次 angular 消化观察者以查看它是否已更改时,都必须调用该函数。您应该尽量让您的模板保持 干燥。
在查看 Angularjs 的 FEQ 时,我看到了以下文章:
$rootScope exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject
$rootScope
and set values on it like any other scope. Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives likeng-show
just like values on your local$scope
.Of course, global state sucks and you should use
$rootScope
sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on$rootScope
, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.Conversely, don't create a service whose only purpose in life is to store and return bits of data.
— AngularJS FAQ - $rootScope exists, but it can be used for evil
所以我的疑问是为什么不建议将 $rootScope 作为全局函数用于函数?有没有性能问题?
全局变量被滥用
$rootScope
几乎是一个全局变量并且有它的位置,但肯定被大多数使用它的人滥用。这些是通常不应使用全局变量的原因。
Non-locality -- Source code is easiest to understand when the scope of its individual elements are limited. Global variables can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.
No Access Control or Constraint Checking -- A global variable can be get or set by any part of the program, and any rules regarding its use can be easily broken or forgotten. (In other words, get/set accessors are generally preferable over direct data access, and this is even more so for global data.) By extension, the lack of access control greatly hinders achieving security in situations where you may wish to run untrusted code (such as working with 3rd party plugins).
Implicit coupling -- A program with many global variables often has tight couplings between some of those variables, and couplings between variables and functions. Grouping coupled items into cohesive units usually leads to better programs.
Concurrency issues -- if globals can be accessed by multiple threads of execution, synchronization is necessary (and too-often neglected). When dynamically linking modules with globals, the composed system might not be thread-safe even if the two independent modules tested in dozens of different contexts were safe.
Namespace pollution -- Global names are available everywhere. You may unknowingly end up using a global when you think you are using a local (by misspelling or forgetting to declare the local) or vice versa. Also, if you ever have to link together modules that have the same global variable names, if you are lucky, you will get linking errors. If you are unlucky, the linker will simply treat all uses of the same name as the same object.
Memory allocation issues -- Some environments have memory allocation schemes that make allocation of globals tricky. This is especially true in languages where "constructors" have side-effects other than allocation (because, in that case, you can express unsafe situations where two globals mutually depend on one another). Also, when dynamically linking modules, it can be unclear whether different libraries have their own instances of globals or whether the globals are shared.
Testing and Confinement - source that utilizes globals is somewhat more difficult to test because one cannot readily set up a 'clean' environment between runs. More generally, source that utilizes global services of any sort (e.g. reading and writing files or databases) that aren't explicitly provided to that source is difficult to test for the same reason. For communicating systems, the ability to test system invariants may require running more than one 'copy' of a system simultaneously, which is greatly hindered by any use of shared services - including global memory - that are not provided for sharing as part of the test.
来源: http://c2.com/cgi/wiki?GlobalVariablesAreBad
在 Angular
中共享数据在 Angular 中跨控制器共享数据时,您应该使用服务。使用自定义服务,您可以创建 getter 和 setter 方法。您将它注入到您需要它的控制器中,并可以在您的应用程序中使用它。
不存在性能问题。它实际上可以将您的性能提高 时间的一部分 ,因为您不需要依赖注入大量服务。
但它是设计的一个大问题。考虑一个大型应用程序,它有几十个视图、复杂的组件并绑定到一个众所周知的 API 数量(例如 Twitter、Flickr、Facebook、OAuth 等)。
您不会单独开发此应用程序。会出现以下问题:
命名空间
您在 Facebook API 上工作,其他人在 Twitter API 上工作。你们都认为对函数使用 $rootScope
是个好主意,并且都编写了 $rootScope.login
函数。在做 git merge
时你会如何解决这个问题?你需要命名空间,唉,你需要开发两个服务myFacebookAPI
,myTwitterAPI
然后可以实现相同的登录接口。(login(user,pw)
)。请注意,当您可以执行以下操作时,这使您能够抽象出您在控制器中处理的实际社交网络:
$scope.callAction = function (action) {
var service;
if ($scope.serviceSelected === 'fb') {
service = myFacebookAPI;
} else {
service = myTwitterAPI;
}
service[action]();
};
测试
在进行专业开发时,您会编写测试。 Angular 为您提供了对服务等进行自动化测试的工具,但您无法以同样舒适的方式测试分配给 $rootScope
的内容。
其他问题也会出现,但我想这应该足够你自己考虑了。
我过去已经回答过这个问题,但你问这些问题很好。
$rootScope exists, but it can be used for evil Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
非隔离作用域是分层的,但大多数开发人员应该使用具有隔离作用域的指令。 AngularJS 作用域的层级性质是 许多 应用程序中错误的来源。这是一个我喜欢称之为 scope bleeding 的问题,其中范围 属性 在 DOM 树中的某处被神奇地修改了,而你不知道为什么。
Angular 的 default 行为是针对固有范围的,这使得一个控制器很容易更新另一个控制器管理的内容,依此类推.这就是在源代码之间创建意大利面条式连接的方式。使得维护该代码变得非常困难。
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope and set values on it like any other scope.
不,那是不正确的。 AngularJS 允许你定义诸如常量、值和服务之类的东西。这些东西可以注入到路由、控制器和指令中。这就是你如何让你的应用程序全局访问的东西,如果你想让你的控制器或指令可测试,你也可以这样做。单元测试编写者不知道指令或控制器所依赖的 $rootScope 中应该有哪些属性。他们必须假设 $rootScope 没有变异来提供服务或数据。
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language.
问题不是 $rootScope,而是人们用它做什么。许多应用程序将当前用户、身份验证令牌和会话数据添加到 rootScope 中。这最终会在模板中大量使用(如果用户登录则显示 X,否则显示 Y)。问题是 HTML 不传达范围层次结构。所以当你看到 {{user.firstname + ' ' + user.lastname}}
时,你不知道变量 user
是从哪里来的。第二个问题是子作用域可以隐藏根属性。与前面的示例一样,如果指令执行此操作 scope.user = 'bla bla bla'
。它没有替换 rootScope 上的值。它隐藏了它。现在你在模板中得到了一些奇怪的意想不到的东西,你不知道为什么变量 user
发生了变化。
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
Angular 的 $cacheFactory
和 $templateCache
是仅存储数据的服务示例。我认为作者试图鼓励在 Angular 的模块中使用常量和值,但这并不是一个好的描述。
So My doubt is why $rootScope is not recommended for functions as a global function? Is there any performance issue?
$rootScope 是 angular.config(..)
期间唯一可用的范围。如果这是唯一的时间,则可以在此期间修改范围。例如;您可能需要在 应用程序启动之前 注入 API 密钥或 Google 分析变量。
any 作用域上的函数通常不是一个好主意。主要是因为作用域中的所有内容都在模板的表达式中被消化。函数倾向于隐藏 繁重的操作。在调用函数时,通过读取 HTML 无法判断模板的重量。我见过像 getHeight()
这样的范围函数,其中函数本身执行 3 级嵌套循环。每次 angular 消化观察者以查看它是否已更改时,都必须调用该函数。您应该尽量让您的模板保持 干燥。