atian25 / blog

天猪部落阁 http://atian25.github.io
1.59k stars 107 forks source link

AngularJS性能优化心得 #5

Closed atian25 closed 5 years ago

atian25 commented 9 years ago

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

本文针对的读者:

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

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

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

concepts-runtime

参考《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();
  }
});
<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

$http.get('http://path/to/url').success(function(data){
  $scope.name = data.name;
  $timeout(function(){
    //do sth later, such as log
  }, 0, false);
});

刷新数据时,我们常这么做:$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行就超标了。 下图这个只是一个很简单的列表,还不是表格,就已经这么多个了: scope-binding-src 但其实很多属性显示后是几乎不会变更的, 这时候就没必要双向绑定了。(不知道angular为何不考虑此类场景) 如下图,改为bindonceangular-once后减少了很多: scope-binding-once

update: 1.3.0b10开始支持内建单次绑定, {% raw %}{{::variable}}{% endraw %} 设计文档: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);
});

慎用事件

zhangnanMoo commented 9 years ago

赞赞赞!

daviiz commented 9 years ago

mark!!

cpsa3 commented 9 years ago

赞,谢谢分享!

island205 commented 9 years ago

yurychika commented 9 years ago

zan

vitrum commented 9 years ago

马克后看,赞!

OXOYO commented 9 years ago

Nice

daviiz commented 9 years ago

mark

acs1899 commented 9 years ago

mark

andysjt commented 9 years ago

mark

zwh8800 commented 9 years ago

Nice!

junstyle commented 9 years ago

mark

yyjazsf commented 9 years ago

mark

qizhiyu commented 9 years ago

mark

wikieswan commented 8 years ago

Tomorrow0329 commented 8 years ago

Mark!

yangbai1991 commented 8 years ago

赞!

Arguseye commented 8 years ago

赞!

f2eMrWu commented 8 years ago

新人学到了许多。非常感谢

junfeisu commented 8 years ago

very good thanks

kiroInn commented 8 years ago

学习了~

njleonzhang commented 8 years ago

多谢,很好

liyj144 commented 8 years ago

good, mark

floraluo commented 8 years ago

mark

ghost commented 8 years ago

Thank you

changwei0708 commented 8 years ago

原文链接, http://www.cnblogs.com/rubylouvre/p/3776971.html

atian25 commented 8 years ago

image

@changwei0708 我只能呵呵了... 自己看正文里面的那些图片, 就是我这边九游的应用的截图.

正妹 @RubyLouvre 你这事做的太不地道了吧, 全文转载我的, 还不注明出处.

diamont1001 commented 8 years ago

去博客园举报他

willworks commented 8 years ago

我想起了当年知乎约战的事情

atian25 commented 8 years ago

@changwei0708

知道为何很多地方都写着出处么? 因为它来源自我之前在多看上的读书笔记

参考《mastering web application development with angularjs》 P314

image

zack-lin commented 8 years ago

@RubyLouvre 怎么看?

kinglion commented 8 years ago

@RubyLouvre 怎么看?

releasethecow commented 8 years ago

@RubyLouvre 怎么看?

changwei0708 commented 8 years ago

@atian25 看到楼上的@我就放心了

changwei0708 commented 8 years ago

@diamont1001 @willworks 不要啊,闹着玩的

menglexing commented 8 years ago

不嫌事大。。。

zhanglun commented 8 years ago

image 看不太懂了。。这个发布时间,,,

感觉有好戏了 :smile:

atian25 commented 8 years ago

@zhanglun 因为原文在这里,后面才迁移到 issue, https://github.com/atian25/atian25.github.io/blob/master/2014/05/09/angular-performace/index.html

RubyLouvre commented 8 years ago

什么事,我从是一个到处飘着广告的网站中搬过来的。不知原作者啊。

menglexing commented 8 years ago

恩,我相信 @RubyLouvre 这点素质还是有的

RubyLouvre commented 8 years ago

我可以将你这个地址 加到我博文中

atian25 commented 8 years ago

@RubyLouvre 好吧~ 注明下吧, 不然哪天我又被你的粉丝纠正了~

ngot commented 8 years ago

原来是偷的别人的赃物。。。

Justineo commented 8 years ago

原来不知原作者就可以当做自己的东西发布了,厉害。这个借口可以用一辈子。

hacke2 commented 8 years ago

我觉的就算是到处飘着广告的网站也还是得贴上那个网站地址。。

djyde commented 8 years ago

我不太明白为什么明明是转载也不标明非原创。。。

fengjx commented 8 years ago

mark

shauvet commented 7 years ago

受教了,还是感谢下。。。

ps:下面一堆大神出没。。。

HughDai commented 7 years ago

mark

baishusama commented 7 years ago

比较好奇是哪三本书。。