尽量减少 Watcher 的数量:
以下代码均会产生 watcher:
$scope.$watch{{}}数据绑定- 大多数 ng directive,如
ng-show,ng-hide $scope变量的属性及方法,如$scope.method = function () {}- DOM filter,如
{{ title | greet}} ng-repeatwacher 将会存储在各自相应的$scope.$$wachers里面。当有新的 wacher 产生时,则会自动添加到$scope.$$acher里面。
watcher 在以下情况下会运行(digest cycle):
- 用户的操作,如
ng-click等。大多数内置的 directive 都会调用$scope.$apply来实现 digest cycle. ng-changeng-model$http请求事件$qpromise 对象的 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 。