尽量减少 Watcher
的数量:
以下代码均会产生 watcher:
$scope.$watch
{{}}
数据绑定- 大多数 ng directive,如
ng-show
,ng-hide
$scope
变量的属性及方法,如$scope.method = function () {}
- DOM filter,如
{{ title | greet}}
ng-repeat
wacher 将会存储在各自相应的$scope.$$wachers
里面。当有新的 wacher 产生时,则会自动添加到$scope.$$acher
里面。
watcher 在以下情况下会运行(digest cycle):
- 用户的操作,如
ng-click
等。大多数内置的 directive 都会调用$scope.$apply
来实现 digest cycle. ng-change
ng-model
$http
请求事件$q
promise 对象的 resolve$timeout
$interval
- 手动的调用
$scope.$digest
以及$socpe.$apply
当执行 digest cycle 时,会执行$scope.$$wachers
里面的所有回调函数。当某个wacher
函数改变了某个被监听了的 model 时,则会重新执行 digest cycle ,直到数据稳定不再变化为止。
1、使用 One-Time binding
从
1.3.0
版本开始,Angular 开始支持 One-Time Binding ,即 model 只会被计算一次,当计算完成之后则会删除该 model 的所有 watcher
,从而起到性能优化的作用。// 传统写法
<p>{{ title }}</p>
// One-Time binding
<p>{{ ::title }}</p>
2、$scope.$digest
与 $scope.$apply
$digest
与 $apply
均可以触发 Angular 的 digest loop ,唯一不同的是, $apply
会触发 $rootScope.$digest()
,而,$digest
只会触发当前 $scope
的 $scope.$digest()
,因此,$apply
会重新计算页面所有的 $scope
的 model,而 $digest
只会重新计算当前 $scope
以及它的子 scope。 当需要让 Angular 重新计算的 model 是位于当前 scope 里面时,应该使用 $digest
,避免使用 $apply
。3、尽量减少在 DOM 使用 filter
DOM里面的每一个
filter
在每次 $digest
loop 里里面至少会执行两次,因此,如果项目一旦稍具规模的话,filter
的开销是非常大的。 相对于在 DOM 里面使用 filter
,可以先在 JS 里面,使用 Angular 提供的 $filter
服务,先将 model 转化一下,再将它渲染在 DOM 里面:// DOM 里面的 filter:
<div> {{filter_expression | filter : expression : comparator}} </div>
// 例如:
<div> {{ currentTime | time }} </div>
// JS 里面的 filter:
$filter('filter')(array, expression, comparator);
// 例如:
angular.module('app').controller('ctrl', function ($scope, $filter) {
var currentTime = new Date();
$scope.currentTime = $filter('time')(currentTime);
});
4、可以使用 $watchCollection
来取代 深度的 $watch
Angular 的
$watch
有两种调用方式,一种是传递两个参数,一种是传递三个参数。第三个参数表示是否执行深度检查。深度检查意味着 Angular 会检查该对象的每一个属性是否发生变化。 而 $watchCollection
在大部分时候和 $watch
的深度检查一样,只不过,$watchCollection
指检查当前对象的第一层属性。而不像 $watch
的深度检查一样,会检查所有的属性。5、设置 ngModel
的 debounce
ng-model-option="{debounce: 250}"
这一行配置会告诉 Angular,当 model 的数据在 250 毫秒之内没有发生变化的时候,才会更新 digest cycle 。比如可以用在搜索框,使得用户的输入与实时请求搜索结果有一个250毫秒的延迟。6、如果 ng-if
更加适合的话,尽量使用 ng-if
取代 ng-show
/ ng-hide
ng-show
与 ng-hide
实质只是为元素添加一个 ng-hide
的类,并且强制设置样式为 display: none
。尽管可以实现元素的隐藏,但是其内部的 watcher 仍然存在,仍然会在每次 digest cycle 进行计算。倘若当元素隐藏之后,没有必要再计算元素内部的 model 时,可以使用 ng-if
。ng-if
会把整个元素从 DOM 中移除,并且删除里面的 watcher 。