最近在开发Hybrid APP (我用的是Ionic Frameworks) 的过程中,随着首页栏目的逐渐增加,APP在手机上的执行效率越来越低,有时在切换频道的时候会有明显的卡顿和执行延迟。

在检查完代码逻辑和算法后,并没有发现什么问题 (网络通讯,本地缓存)。最近在翻阅代码的过程中,突然意识到可能是由于频道增加,页面中双向绑定使用数量变多,导致 AngularJS 在作 digest loop 的时候,由于 $$watchers 数量过多导致程序变慢。

要想确定猜想,需要先能统计到页面中随着频道进入$$watchers的数量,于是写了如下代码,在Chrome的控制台中执行,便可以方便的进行统计。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function getWatchers(root) {
root = angular.element(root || document.documentElement);
var watcherCount = 0;

function getElemWatchers(element) {
var isolateWatchers = getWatchersFromScope(element.data().$isolateScope);
var scopeWatchers = getWatchersFromScope(element.data().$scope);
var watchers = scopeWatchers.concat(isolateWatchers);
angular.forEach(element.children(), function (childElement) {
watchers = watchers.concat(getElemWatchers(angular.element(childElement)));
});
return watchers;
}

function getWatchersFromScope(scope) {
if (scope) {
return scope.$$watchers || [];
} else {
return [];
}
}

return getElemWatchers(root);
}
getWatchers().length

随即发现,在频道页面不断加载的过程中, $$watchers的数量在不断增加,最多的时候有 5000个之多。

发现问题就好解决了。由于频道内容列表页面在一次加载后就不需要再进行变化监听,所以这里打算对代码中的data-binding 部分使用 bindonce 的方式解决。

这里还有两个关于 bindonce 的示例:

使用AngularJS 原有Bind
使用Bindonce