7 简单的性能改进
1)谨慎使用 ng-repeat
在视图中使用 ng-repeat
通常会导致性能不佳,尤其是当存在嵌套的 ng-repeat
时。
这超级慢!
<div ng-repeat="user in userCollection">
<div ng-repeat="details in user">
{{details}}
</div>
</div>
尽量避免嵌套重复。提高 ng-repeat
性能的一种方法是使用 track by $index
(或其他一些 id 字段)。默认情况下,ng-repeat
跟踪整个对象。使用 track by
,Angular 仅通过 $index
或 object id 观察对象。
<div ng-repeat="user in userCollection track by $index">
{{user.data}}
</div>
**使用其他方法,**如分页 ,虚拟滚动 ,无限滚动或限制:尽可能开始,以避免迭代大型集合。
2)绑定一次
Angular 具有双向数据绑定。如果使用太多,它会降低成本。
性能较差
<!-- Default data binding has a performance cost -->
<div>{{ my.data }}</div>
更快的性能 (AngularJS> = 1.3)
<!-- Bind once is much faster -->
<div>{{ ::my.data }}</div>
<div ng-bind="::my.data"></div>
<!-- Use single binding notation in ng-repeat where only list display is needed -->
<div ng-repeat="user in ::userCollection">
{{::user.data}}
</div>
使用 bind once
表示法告诉 Angular 在第一系列摘要周期后等待值稳定。Angular 将在 DOM 中使用该值,然后删除所有观察者,使其成为静态值,并且不再绑定到模型。
{{}}
慢得多。
这个 ng-bind
是一个指令,它将在传递的变量上放置一个观察者。因此,当传递的值确实发生变化时,ng-bind
将仅适用。
另一方面,托架将在每个 tihuan 11 中进行脏检查和更新,即使没有必要。
3)范围功能和过滤器需要时间
AngularJS 有一个摘要循环。你的所有功能都在视图中,并且每次摘要周期运行时都会执行过滤器。每当模型更新时都会执行摘要循环,它可能会降低你的应用程序速度(在加载页面之前可以多次点击过滤器)。
避免这个:
<div ng-controller="bigCalulations as calc">
<p>{{calc.calculateMe()}}</p>
<p>{{calc.data | heavyFilter}}</p>
</div>
更好的方法
<div ng-controller="bigCalulations as calc">
<p>{{calc.preCalculatedValue}}</p>
<p>{{calc.data | lightFilter}}</p>
</div>
控制器可以是:
app.controller('bigCalulations', function(valueService) {
// bad, because this is called in every digest loop
this.calculateMe = function() {
var t = 0;
for(i = 0; i < 1000; i++) {
t += i;
}
return t;
}
// good, because this is executed just once and logic is separated in service to keep the controller light
this.preCalulatedValue = valueService.valueCalculation(); // returns 499500
});
4 位观察者
观察者的表现大幅下降。对于更多的观察者,摘要循环将花费更长时间,UI 将减慢。如果观察者检测到变化,它将启动摘要循环并重新渲染视图。
在 Angular 中有三种方法可以手动监视变量的变化。
$watch()
- 值得改变
$watchCollection()
- 手表收藏变化(手表超过常规 $watch
)
$watch(..., true)
- 尽可能避免这种情况,它将执行深度观察并将降低性能(手表超过 watchCollection
)
请注意,如果你要在视图中绑定变量以创建新手表 - 请使用 {{::variable}}
来防止创建手表,尤其是在循环中。
因此,你需要跟踪你正在使用的观察者数量。你可以使用此脚本统计观察者(归功于 @Words 像 Jared 观察者数量 )
(function() {
var root = angular.element(document.getElementsByTagName('body')),
watchers = [],
f = function(element) {
angular.forEach(['$scope', '$isolateScope'], function(scopeProperty) {
if(element.data() && element.data().hasOwnProperty(scopeProperty)) {
angular.forEach(element.data()[scopeProperty].$$watchers, function(watcher) {
watchers.push(watcher);
});
}
});
angular.forEach(element.children(), function(childElement) {
f(angular.element(childElement));
});
};
f(root);
// Remove duplicate watchers
var watchersWithoutDuplicates = [];
angular.forEach(watchers, function(item) {
if(watchersWithoutDuplicates.indexOf(item) < 0) {
watchersWithoutDuplicates.push(item);
}
});
console.log(watchersWithoutDuplicates.length);
})();
5)ng-if / ng-show
这些功能在行为上非常相似。 ng-if
从 DOM 中删除元素,而 ng-show
只隐藏元素但保留所有处理程序。如果你有部分代码不想显示,请使用 ng-if
。
这取决于使用类型,但通常一个比另一个更合适。
-
如果不需要该元素,请使用
ng-if
-
要快速打开/关闭,请使用
ng-show/ng-hide
<div ng-repeat="user in userCollection"> <p ng-if="user.hasTreeLegs">I am special<!-- some complicated DOM --></p> <p ng-show="user.hasSubscribed">I am awesome<!-- switch this setting on and off --></p> </div>
如有疑问 - 请使用 ng-if
并测试!
6)禁用调试
默认情况下,绑定指令和作用域在代码中留下额外的类和标记,以协助各种调试工具。禁用此选项意味着你不再在摘要周期中呈现这些不同的元素。
angular.module('exampleApp', []).config(['$compileProvider', function ($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}]);
7)使用依赖注入来公开你的资源
依赖注入是一种软件设计模式,其中对象被赋予其依赖性,而不是创建它们自身的对象。它是关于删除硬编码的依赖关系,并使其可以在需要时更改它们。
你可能想知道与所有可注入函数的字符串解析相关的性能成本。Angular 通过在第一次之后缓存$ inject 属性来解决这个问题。因此,每次需要调用函数时都不会发生这种情况。
PRO TIP:如果你正在寻找性能最佳的方法,请使用$ inject 属性注释方法。这种方法完全避免了函数定义解析,因为这个逻辑包含在 annotate 函数中的以下检查中:if(!($ inject = fn。$ inject))。如果$ inject 已经可用,则不需要解析!
var app = angular.module('DemoApp', []);
var DemoController = function (s, h) {
h.get('https://api.github.com/users/angular/repos').success(function (repos) {
s.repos = repos;
});
}
// $inject property annotation
DemoController['$inject'] = ['$scope', '$http'];
app.controller('DemoController', DemoController);
专题提示 2:你可以在与 ng-app
相同的元素上添加 ng-strict-di
指令,以选择严格的 DI 模式,只要服务尝试使用隐式注释,就会抛出错误。例:
<html ng-app="DemoApp" ng-strict-di>
或者如果你使用手动引导:
angular.bootstrap(document, ['DemoApp'], {
strictDi: true
});