大家都知道,AngularJS 双向数据绑定很 Cool 。简单地说,Angular 在 scope 模型上设置了一个监听队列,用来监听数据变化并更新 view 。每次绑定一个东西到 View 上时 AngularJS 就会往 $watch
队列里插入一条 $watch
,用来检测它监听的 Model 里是否有变化的东西。当浏览器接收到可以被 Angular 执行环境处理的事件时,就会触发 $digest
循环,遍历所有的 $watch
,Model 稳定后结束循环。大多数时候,浏览器速度很快这个过程不长,这不是一个大问题。但如果在很复杂的应用下使用不当会造成性能问题,比如说表格树组件中滥用双向数据绑定很容易造成界面很卡。
Angular 为每个 $digest
循环添加了一个监听:
{{expression}}
:在您的模板(以及其他任何有表达式的地方)
$scope.$ watch('expression / function')
:在你的 JavaScript 中
监听计数
Batarang等插件已经有监听计数功能,不过我觉得它们这个功能好像不准确。下面这个简单的脚本将帮助您识别应用的绝了大部分监听:
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);
// 此处应该是 concat 方法,但服务器不支持
var watchers = scopeWatchers.contact(isolateWatchers);
angular.forEach(element.children(), function (childElement) {
watchers = watchers.contact(getElemWatchers(angular.element(childElement)));
});
return watchers;
}
function getWatchersFromScope(scope) {
if (scope) {
return scope.$$watchers || [];
} else {
return [];
}
}
return getElemWatchers(root);
}
getWatchers().length
只需将其粘贴到您的控制台(或使用 Chrome 浏览器片段)并如下使用:
// 在整个页面上获取所有监听
getWatchers();
// 获取特定元素(及其子元素)的
getWatchers(document.body);
// 在 Chrome 开发工具中选择感兴趣的元素
getWatchers($0);
它会返回你给出的元素及其所有子元素的监听。
减少你的监听数量
幸运的是,AngularJS 1.3 以后增加一次性绑定操作符 ::
,这样可以减少模板中的监听数量。如果你只能使用低版本的 AngularJS 中,那么好有两个替代解决方案
感兴趣的话,可以试一试,它们可以很好地减少你的监听数量。
评论 (0)