资讯专栏INFORMATION COLUMN

angular性能优化心得

guqiu / 3009人阅读

摘要:本文针对的读者具备性能优化的相关知识雅虎条性能优化原则高性能网站建设指南等拥有实战经验。这种机制能减少浏览器次数,从而提高性能。仅会检查该和它的子,当你确定当前操作仅影响它们时,用可以稍微提升性能。

搬运自: http://atian25.github.io/2014/05/09/angular-performace/

  

不知不觉,在项目中用angular已经半年多了,踩了很多坑。
趁着放假,把angular的3本书都看了遍,结合这半年的经验,是该做个总结了。
希望可以给大家带来启示,少踩点坑。

本文针对的读者:
- 具备JavaScript性能优化的相关知识(雅虎14条性能优化原则《高性能网站建设指南》等)
- 拥有angular实战经验。

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

谈起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不会仅对{{variable}}建立watcher,而是对整个p标签。
双括号应该被span包裹,因为watch的是外部element

  

参考《mastering web application development with angularjs》 P314

plain text other {{variable}} plain text other

//改为:

plain text other plain text other

//或

plain text other {{variable}} plain text other

$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);
});

$evalAsync vs $timeout

http://stackoverflow.com/questions/17301572/angularjs-evalasync-vs-timeout

directive中执行的$evalAsync, 会在angular操作DOM之后,浏览器渲染之前执行。

controller中执行的$evalAsync, 会在angular操作DOM之前执行,一般不这么用。

而使用$timeout,会在浏览器渲染之后执行。

优化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

使用单次绑定

我们都知道angular建议一个页面最多2000个双向绑定,但在列表页面通常很容易超标。
譬如一个滑动到底部加载下页的表格,一行20+个绑定, 展示个100行就超标了。
下图这个只是一个很简单的列表,还不是表格,就已经这么多个了:

但其实很多属性显示后是几乎不会变更的, 这时候就没必要双向绑定了。(不知道angular为何不考虑此类场景)
如下图,改为bindonce或angular-once后减少了很多:

update:
1.3.0b10开始支持内建单次绑定, {{::foo}}
设计文档:http://t.cn/RvIYHp9
commit: http://t.cn/RvIYHpC
目前该特性的性能似乎还有待优化(2x slower)

慎用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);
});
慎用事件

减少事件广播,使用双向数据绑定或共享service等方法来代替。

$broadcast会遍历scope和它的子scope,而不是只通知注册了该事件的子scope。

一个优化方式是使用$emit, 参见https://github.com/angular/angular.js/issues/4574

1.2.7版本对事件做过一个优化,参见https://github.com/angular/angular.js/blob/master/CHANGELOG.md#127-emoji-clairvoyance-2014-01-03

对高频的事件做缓冲限速,避免触发太频繁。

directive

跟scope数据无关的操作放在compile阶段,它只执行一次。

除了directive外其他地方,特别是controller里面不要操作dom, 尤其是绑定到scope后,便是灾难。

改变以前使用JQuery那样以DOM为中心的思维,拥抱以数据为中心的思维。参见
> 参见: http://stackoverflow.com/questions/14994391/how-do-i-think-in-angularjs-if-i-have-a-jquery-background
> 翻译: http://blog.jobbole.com/46589/

使用Batarang来分析性能

AngularJS Batarang是官方提供的chrome插件

搬运自: http://atian25.github.io/2014/05/09/angular-performace/

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78079.html

相关文章

  • Angular 8 中,我们可以期待些什么

    摘要:在理想的情况下,我们甚至可以立即将应用程序升级到。于是,在中,我们可以得到些什么正如我们所看到的,的新增特性除之外并不是很亮眼,尽管这些特性非常好用,但对于大多数应用程序来说并不重要。 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 本文由葡萄城翻译并发布 showImg(https://segmentfault.com/img/bVbrk...

    LiveVideoStack 评论0 收藏0
  • 2017-07-01 前端日报

    摘要:前端日报精选腾讯前端团队社区源码分析入门指南一些关于使用的心得基本类型与引用类型知多少掘金中文第期框架选型周刊第期入门系列模块车栈重构基于的网络请求库某熊的全栈之路的那些奇技淫巧的平凡之路模仿写个数组监听掘 2017-07-01 前端日报 精选 Why you shouldn`t use Preact, Fast-React, etc. to replace React today -...

    _DangJin 评论0 收藏0
  • 4月份前端资源分享

    摘要:更多资源请文章转自月份前端资源分享关于的思考一款有趣的动画效果跨站资源共享之二最流行的编程语言能做什么到底什么是闭包的第三个参数跨域资源共享详解阮一峰前端要给力之语句在中的值周爱民中国第二届视频花絮编码规范前端工程师手册奇舞周刊被忽视的 更多资源请Star:https://github.com/maidishike... 文章转自:https://github.com/jsfron...

    jsdt 评论0 收藏0
  • 火星积雪,一个应用网站的构建之路!

    摘要:但是在第一次上线后,发现自己的网页打开后,加载的速度需要秒,当时第一感觉就是,我是不是应该换框架最终在网络上摸索出来一系列的解决方案,得到了现在只要秒就可以完成加载任务这一系列的解决方案我会在整理好后再告诉大家。 火星积雪 摘要:火星积雪 这个是目前正在开发的一个项目,主要目的是为了提供一个快捷的集成应用的,这么一个小应用中心! 项目框架 angular5 angular-cli ...

    warmcheng 评论0 收藏0

发表评论

0条评论

guqiu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<