通过脏检查$scope
对象
Angular array
在$scope
对象中维护了一个简单的观察者。如果您检查任何内容$scope
,都会发现其中包含array
被叫$$watchers
。
每个观察者都是一个object
包含其他内容的
- 观察者正在监视的表达式。这可能只是一个
attribute
名称,或更复杂。
- 表达式的最后一个已知值。可以对照表达式的当前计算值进行检查。如果值不同,则观察者将触发该功能并将其标记
$scope
为脏。
- 如果观察者脏了将执行的功能。
观察者的定义方式
在AngularJS中定义监视程序的方式有很多。
您可以显式$watch
显示attribute
on $scope
。
$scope.$watch('person.username', validateUnique);
您可以{{}}
在模板中放置插值(将在当前模板上为您创建一个观察器$scope
)。
<p>username: {{person.username}}</p>
您可以要求一个指令,例如为ng-model
您定义观察者。
<input ng-model="person.username" />
该$digest
循环核对其最后的值所有观察家
当我们通过常规渠道(ng-model,ng-repeat等)与AngularJS进行交互时,指令将触发摘要周期。
摘要循环是其所有子级的深度优先遍历$scope
。对于每个$scope
object
,我们对其进行迭代$$watchers
array
并评估所有表达式。如果新的表达式值与上一个已知值不同,则调用观察者的函数。此函数可能会重新编译DOM的一部分,重新计算on的值$scope
,触发an AJAX
request
,而您需要执行此操作。
遍历每个范围,并评估每个watch表达式并对照最后一个值进行检查。
如果触发了监视程序,则$scope
表示该监视程序是脏的
如果触发了观察者,则应用程序知道某些更改,并且$scope
标记为脏。
监视程序功能可以更改$scope
父级上或父级上的其他属性$scope
。如果一个$watcher
函数被触发,我们不能保证其他函数$scope
仍然干净,因此我们再次执行整个摘要循环。
这是因为AngularJS具有双向绑定,因此可以将数据传递回$scope
树。我们可能会更改$scope
已经消化的较高值。也许我们改变的价值$rootScope
。
如果$digest
脏,我们将$digest
再次执行整个循环
我们不断循环遍历整个$digest
循环,直到摘要循环$watch
变得干净(所有表达式的值与上一个循环中的值相同),或者达到摘要极限。默认情况下,此限制设置为10。
如果达到摘要限制,AngularJS将在控制台中引发错误:
10 $digest() iterations reached. Aborting!
摘要在机器上很难,但对开发人员来说很容易
如您所见,每当AngularJS应用程序中发生任何更改时,AngularJS都会检查$scope
层次结构中的每个观察者,以查看如何响应。对于开发人员来说,这是一个巨大的生产力提升,因为您现在几乎不需要编写任何接线代码,AngularJS只会注意到值是否已更改,并使应用程序的其余部分与更改保持一致。
从机器的角度来看,这是非常低效的,如果我们创建了过多的观察者,这将使我们的应用程序运行缓慢。Misko引用了大约4000名观察者的数据,然后您的应用在较旧的浏览器上会感觉缓慢。
例如,如果您ng-repeat
的数量很大JSON
array
,则很容易达到此限制。您可以使用一次性绑定之类的功能来缓解这种情况,从而无需创建观察者即可编译模板。
如何避免创建过多的观察者
每次您的用户与您的应用进行交互时,应用中的每个观察者都将至少评估一次。优化AngularJS应用的很大一部分是减少$scope
树中观察者的数量。一种简单的方法是一次性绑定。
如果您的数据很少更改,则只能使用::语法将其绑定一次,如下所示:
<p>{{::person.username}}</p>
要么
<p ng-bind="::person.username"></p>
仅当呈现包含模板并将数据加载到中时,才会触发绑定$scope
。
当您有ng-repeat
很多物品时,这一点尤其重要。
<div ng-repeat="person in people track by username">
{{::person.username}}
</div>