脏数据检查 != 轮询检查更新

谈起angular的脏检查机制(dirty-checking), 常见的误解就是认为: ng是定时轮询去检查model是否变更。
其实,ng只有在指定事件触发后,才进入$digest cycle

  • DOM事件,譬如用户输入文本,点击按钮等。(ng-click)
  • XHR响应事件 ($http)
  • 浏览器Location变更事件 ($location)
  • Timer事件($timeout$interval)
  • 执行$digest()$apply()

参考《mastering web application development with angularjs》 P294

$digest后批量更新UI

传统的JS MVC框架, 数据变更是通过setter去触发事件,然后立即更新UI。
而angular则是进入$digest cycle,等待所有model都稳定后,才批量一次性更新UI。
这种机制能减少浏览器repaint次数,从而提高性能。

参考《mastering web application development with angularjs》 P296
另, 推荐阅读: 构建自己的AngularJS,第一部分:Scope和Digest

提速 $digest cycle

关键点

  • 尽少的触发$digest (P310)
  • 尽快的执行$digest

优化$watch

  • $scope.$watch(watchExpression, modelChangeCallback), watchExpression可以是String或Function。
  • 避免watchExpression中执行耗时操作,因为它在每次$digest都会执行1~2次。
  • 避免watchExpression中操作dom,因为它很耗时。
  • console.log也很耗时,记得发布时干掉它。(用grunt groundskeeper)
  • ng-if vs ng-show, 前者会移除DOM和对应的watch
  • 及时移除不必要的$watch。(angular自动生成的可以通过下文介绍的bindonce) > 参考《mastering web application development with angularjs》 P303~309
var unwatch = $scope.$watch("someKey", function(newValue, oldValue){
//do sth...
if(someCondition){
//当不需要的时候,及时移除watch
unwatch();
}
});
  • 避免深度watch, 即第三个参数为true

    参考《mastering web application development with angularjs》 P313

  • 减少watch的变量长度
    如下,angular不会仅对{% raw %}{{variable}}{% endraw %}建立watcher,而是对整个p标签。
    双括号应该被span包裹,因为watch的是外部element

    参考《mastering web application development with angularjs》 P314
    {% raw %}

<p>plain text other {{variable}} plain text other</p>
//改为:
<p>plain text other <span ng-bind='variable'></span> plain text other</p>
//或
<p>plain text other <span>{{variable}}</span> plain text other</p>

{% endraw %}

$apply vs $digest

  • $apply会使ng进入$digest cycle, 并从$rootScope开始遍历(深度优先)检查数据变更。
  • $digest仅会检查该scope和它的子scope,当你确定当前操作仅影响它们时,用$digest可以稍微提升性能。 > 参考《mastering web application development with angularjs》 P308

延迟执行

  • 一些不必要的操作,放到$timeout里面延迟执行。
  • 如果不涉及数据变更,还可以加上第三个参数false,避免调用$apply
  • 对时间有要求的,第二个参数可以设置为0。
$http.get('http://path/to/url').success(function(data){
$scope.name = data.name;
$timeout(function(){
//do sth later, such as log
}, 0, false);
});

优化ng-repeat

限制列表个数

  • 列表对象的数据转换,在放入scope之前处理。如$scope.dataList = convert(dataFromServer)
  • 可以使用ngInfiniteScroll来做无限滚动。

使用 track by

刷新数据时,我们常这么做:$scope.tasks = data || [];,这会导致angular移除掉所有的DOM,重新创建和渲染。
若优化为ng-repeat="task in tasks track by task.id后,angular就能复用task对应的原DOM进行更新,减少不必要渲染。
参见:http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by

慎用filter

在$digest过程中,filter会执行很多次,至少两次。
所以要避免在filter中执行耗时操作

参考《mastering web application development with angularjs》 P136

angular.module('filtersPerf', []).filter('double', function(){
return function(input) {
//至少输出两次
console.log('Calling double on: '+input);
return input + input;
};
});

可以在controller中预先处理

//mainCtrl.js
angular.module('filtersPerf', []).controller('mainCtrl', function($scope, $filter){
$scope.dataList = $filter('double')(dataFromServer);
});

慎用事件

directive

最新文章

  1. oracle打补丁
  2. linux 下 systemd-udevd 服务解析
  3. PinPhoto On OS X
  4. 使用 html5 postMessage 实现跨域
  5. netty4 连通步骤
  6. 如何才能学到Qt的精髓——信号槽之间的无关性,提供了绝佳的对象间通讯方式,QT的GUI全是自己的一套,并且完全开源,提供了一个绝好机会窥视gui具体实现
  7. Leetcode - Reverse Words
  8. HDOJ(HDU) 1563 Find your present!(异或)
  9. 关于Get和Post
  10. JavaScript面向对象旅程(下)
  11. Learn Plan
  12. Android性能优化典例(一)
  13. 高并发秒杀系统--SpringMVC整合
  14. 机器学习入门 - Google的机器学习速成课程
  15. xcodebuild构建时报错unknown error -1=ffffffffffffffff Command /bin/sh failed with exit code 1
  16. 【夯实PHP基础】PHPUnit -- PHP测试框架
  17. Java线程池参数
  18. {python}完成完整的温度转换程序 猜数字游戏(猜价格,猜年龄等) 解析身份证号、学号不同片段的含义
  19. Java Bitset
  20. iOS基础知识之归档和解档

热门文章

  1. Mybatis传递参数的几种方式
  2. RabbitMQ Go客户端教程1——HelloWorld
  3. CVE-2017-11882(Office远程代码执行)
  4. python爬取网络中的QQ号码
  5. RestTemplate踩坑 之 ContentType 自动添加字符集
  6. 反射操作dll类库之普通类和各种方法调用
  7. JVM知识(一) 求你了,别再说Java对象都是在堆内存上分配空间的了!
  8. 最长公共子序列(LCS动态规划)?
  9. XML常用解析API有哪几种?
  10. springboot 设定访问项目的根路径