OurJS


OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;

欢迎您订阅我们的技术周刊


我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,

欢迎分享您的观点,经验,技巧,心得

让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;


本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(at)ourjs.com

AngularJS在大型单页面应用中的性能优化(二)


分享到
分类 JS学习   关键字 JavaScript   发布 kris  1420030029657
注意 转载须保留原文链接,译文链接,作者译者等信息。  
注* 相关文章 AngularJS在大型单页面应用中的性能优化(一)

7 列表问题


7.1 长列表(Lists)


尽一些可能避免长列表。ng-repeat会进行了一些很重的DOM操作(更不用说对$$watchers的污染),所以无论是在分页或是在无限滚动中,尽量使用小型数据进行渲染。

7.2 过滤器(Filters)


要尽量避免使用过滤器。他们会在每个更新周期运行两次,每当发生任何改变时运行一次,另一次是收集更深层次的改变时触发。所以不要直接从内部列表中移除对象,使用CSS控制即可。(注* 用添加CSS类名去隐掉他们)

渲染时的 $index 值并不是真正的数组索引值,它豪无价值。但是排好序的数组索引,无法让你遍历到所有列表中的域。

7.3 更新 ng-repeat


当使用ng-repeat时要尽量避免对全局列表的刷新。ng-repeat会产生一个$$hashkey属性和一系统唯一的项。这意味着当你调用 scope.listBoundToNgRepeat = serverFetch() 时会引起对整个列表的重新刷新。会通知执行所有的watchers并触发每一个元素,这是非常消耗性能的。

这里有两种解决方案。一种是维护两个集合,和带有过虑器(filter)的ng-repeat(基本上需要自定义同步逻辑,因此算法更复杂,可维护性更差),另一种方案是使用track by去指定你自己的key(Angular 1.2 开始支持,只需要很少的同步逻辑)。

总之:

scope.arr = mockServerFetch();

会比下面的这种慢

var a = mockServerFetch();
for(var i = scope.arr.length - 1; i >=0; i--){
  var result = _.find(a, function(r){
    return (r && r.trackingKey == scope.arr[i].trackingKey);
  });
  if (!result){
    scope.arr.splice(i, 1);
  } else {
    a.splice(a.indexOf(scope.arr[i]), 1);
  }
}
_.map(a, function(newItem){
  scope.arr.push(newItem);
});


这种

<div ng-repeat="a in arr track by a.trackingKey">


比上面的慢些

<div ng-repeat="a in arr">

测试用例可以在这里 http://plnkr.co/qRlVT52vaMreEkXvhQ3B 找到


8 渲染问题


另一个引起Angular应用慢的原因是不正确地使用 ng-hide/ ng-show 或 ng-switch。

ng-hide 和 ng-show 简单地对CSS display属性进行切换。这意味着表面上看不见的东西其实还存在于域中, 所有的$$watchers还是会被触发。

ng-if 和 ng-switch实际上从DOM中完全移除了,相应的域也会被移除。性能差异显而易见。

9. 更新周期问题


9.1 绑定


尽量减少你的绑定。在Angular 1.3中这里有一个新的一次绑定语法,{{::scopeValue}}。它只会被域执行一次,并不添加到监视器要监视列表中(watcher array).

9.2 $digest() 和 $apply()


scope.$apply 是一个强大的工具,可以让你向Angular引入外部的值。本质上它会触发Angular的所有事件(例如ng-click)。问题是scope.$apply会从根域$rootScope开始,遍历所有的域链,触发每一个域。

scope.$digest只会执行指定域及其相关的域。两种性能差异不言自明。折中的方案是,不触发任何域等到下一个更新周期再更新。

9.3 $watch()


scope.$watch() 已经在很多场景被讨论过的。基本上scope.$watch是不好的设计的一个标志。如果你非要创建一个观察者。记住对它尽可能地解绑。你可以用$watch的返回函数解绑。

var unbinder = scope.$watch('scopeValueToBeWatcher', function(newVal, oldVal) {
   
});
unbinder(); //这一行将watcher从 $$watchers 中移除。

如果你不能早一点解绑,记住在 $on('$destroy') 中进行解绑。

9.4 $on, $broadcast 和 $emit


像$watch一样,他们都是一些很慢的事件,(有可能)遍历整个作用域。他们可能像GOTO一样,让你的程序无法调试。不过幸运地是像$watch一样,他们都可以在完全不需要的时侯解绑。比如在 $on('$destroy')中。

9.5 $destroy


像前面提到的那样,你应该在$on('$destroy')中解绑你所有的事件侦听器,取消任何$timeout的实例,或者任何其它异步执行的交互。这不仅仅是确保安全。还可以让你的域更快地被垃圾回收。不这样做,他们会一直在后台运行。直接你清空CPU和RAM。

另外,解绑DOM上的事件侦听器也非常重要,不这样做很可能在老式浏览器中引起内存泄露。

9.6 $evalAsync


scope.$evalAsync是一个强大的工具。它可以在当前域中执行,并不触发域的更新。evalAsync可以极大地提高你网页的性能。

10 指令问题


10.1 隔离的域(Isolate Scope)和Transclusion


域隔离和Transclusion是Angular最另人激动的特性,它们是Angular的核心组件。

但是这里也有一些权衡,指令不能直接创建一个替换他们父组元素的域。通过隔离的域或Transclusion我们可以创建一个新的对象去跟踪,添加新的监视器,但是这也会降低应用的性能。在添加之前应该仔细想一想有没有这个必要。


10.2 编绎周期


指令(Directive)的compile函数是在域被附加前操作DOM的完美功能(比如说绑定事件)。一个很重要的性能方面是,传入compile函数的元素和属性以原始html模板呈现。只会被运行一次,接下来会直接使用。另外一个重要的点是prelink和postlink的区别。prelink从外向内执行。postlinks从内向外执行。prelink性能稍好一些,因为它不会产生第二次更新周期。但是这时子元素的DOM还未被创建。


11 DOM事件问题


Angular提供了很多预定义的DOM事件指令。ng-click,ng-mouseenter,ng-mouseleave等等。当调用scole.$apply()时这些事件都会被执行。另外一种更有效率的方式是直接在DOM上面绑定addEventListener,并且尽量使用scope.$digest

12 摘要


12.1 AngularJS: 坏的方面


ng-click and other DOM events
scope.$watch
scope.$on
Directive postLink
ng-repeat
ng-show and ng-hide

12.2 AngularJS: 好的方面 (性能)


track by
oneTime bindings with ::
compile and preLink
$evalAsync
Services, scope inheritance, passing objects by reference
$destroy
unbinding watches and event listeners
ng-if and ng-switch


原文地址: 点此
社区评论 ( Beta版 )
OnceDoc 您自己的企业内容管理系统——文档、流程、知识库、报表、网盘All In One

访问404页面,寻找丢失儿童
 热门文章 - 分享最多
  1. 2014年最受欢迎的前十大语言:JavaScript、PHP、Java排前三
  2. 2015年的JavaScript:Angular之类的框架将被库取代
  3. 主流JavaScript MVC框架性能比较测试:Angular vs Backbone vs Ember
  4. 为什么io.js要从Node.js中分裂出来?
  5. HTML5的TCP和UDP Web Socket API草案定稿
  6. AngularJS在大型单页面应用中的性能优化(一)
  7. CSS3实现的响应式字体:自适应视图窗口大小的新单位
  8. JavaScript代码组织结构良好的5个特点[reuqire.js]
  9. io.js新图标logo征集中
  10. 避免Node.js中的命令行注入安全漏洞
  11. AirJD-简单好用的免费建站工具

 相关阅读 - JS学习
  1. AngularJS在大型单页面应用中的性能优化(一)
  2. WebPack:更优秀的模块依赖管理工具,及require.js的缺陷
  3. 在JavaScript的Array数组中调用一组Function方法
  4. 2015年的JavaScript:Angular之类的框架将被库取代
  5. 什么是IndexedDB:Web离线数据库入门简介及基础教程
  6. Node.JS编码规范指南教程:教你优雅地写JavaScript代码
  7. JavaScript的设计缺陷?浮点运算:0.1 + 0.2 != 0.3
  8. Debug调试Node.JS:我们是如何定位内存泄漏和无限循环的
  9. 理解JavaScript中的事件路由冒泡过程及委托代理机制
  10. 用JavaScript制作HTML5动画基础

 关键字 - JavaScript
  1. 如何用CSS将select/option文本居中或居右对齐
  2. 你用什么代码编辑工具开发JavaScript?
  3. JavaScript条形码生成和扫码识别(Barcode scan)开源库
  4. 40行JavaScript代码实现的3D旋转魔方动画效果
  5. 使用Javascript将相对路径地址转换为绝对路径
  6. 给checkbox选择框设置不选中时的值
  7. 用原生HTML5控件实现输入框自动提示(下拉列表补全)功能
  8. JavaScript中怪异的地方
  9. 在JavaScript中创建命名空间的几种写法
  10. JavaScript中的继承,构造函数以及new关键字的作用

 欢迎订阅 - 技术周刊

我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;


 关注我们

我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊

ourjs官方微信号