digest周期会对变量进行脏检查,如果有100个作用域变量,并且我改变了其中一个变量,那么将运行所有变量的监视器。
假设我有100个相互独立的作用域模型变量。如果我更改其中一个变量,则不想检查其他99个变量。有没有方法可以实现这一点?如果有,怎么做?
digest周期会对变量进行脏检查,如果有100个作用域变量,并且我改变了其中一个变量,那么将运行所有变量的监视器。
假设我有100个相互独立的作用域模型变量。如果我更改其中一个变量,则不想检查其他99个变量。有没有方法可以实现这一点?如果有,怎么做?
令人惊讶的是,这通常不是问题,除非表达式很复杂,浏览器即使有成千上万个绑定也不会出现问题。关于 有多少个watchers可以接受
的常见答案是2000
。
解决方案:
从AngularJS 1.3
开始很容易,因为一次性
绑定现在已经是核心功能。
我们可以使用一次性绑定指令(::)
来防止监视器观察不需要监视的变量。在这里,变量只会被监视一次,之后它将不再更新该变量。
HTML:
<ul ng-controller="myCtrl">
<li ng-repeat="item in Lists">{{lots of bindings}}</li>
</ul>
控制器代码:
app.controller('myCtrl', function ($scope, $element) {
$element.on('scroll', function () {
$scope.Lists = getVisibleElements();
$scope.$digest();
});
});
在 $digest
过程中,您只关心 Lists
对象的更改,而不关心单个项的更改。然而,Angular 仍会检查每个 watcher 是否有更改。
指令用于停止和暂停 digest:
app.directive('stopDigest', function () {
return {
link: function (scope) {
var watchers;
scope.$on('stop', function () {
watchers = scope.$$watchers;
scope.$$watchers = [];
});
scope.$on('resume', function () {
if (watchers)
scope.$$watchers = watchers;
});
}
};
});
现在,控制器代码应该被更改:
<ul ng-controller="listCtrl">
<li stop-digest ng-repeat="item in visibleList">{{lots of bindings}}</li>
</ul>
app.controller('myCtrl', function ($scope, $element) {
$element.on('scroll', function () {
$scope.visibleList = getVisibleElements();
$scope.$broadcast('stop');
$scope.$digest();
$scope.$broadcast('resume');
});
});
参考文档: https://coderwall.com/p/d_aisq/speeding-up-angularjs-s-digest-loop
谢谢。
<div>{{:user-data-change:user.name}}</div>
<div>{{:job-data-change:job.name}}</div>
this.refreshUserData().then(() => {
$scope.$broadcast('$$rebind::user-data-change');
});
对于job-data-changed
等类似情况同样适用。
使用此方法,只会在广播时检查user.name
的绑定。
需要注意以下几点:
$emit
和$broadcast
本身可能会影响性能,因此请尝试仅在$scope
树的小部分(具有少量或没有子级的scope
)上调用它们。<div ng-repeat="item in :event-name:items">...</div>
- Andrew Eisenberg
{{::myVar}}
,它只会观察值一次,之后就不会更新值。 - Pankaj Parkar$watchCollection
。 - malix