AngularJS 监听计数

Flying
2016-11-04 / 0 评论 / 157 阅读 / 正在检测是否收录...

大家都知道,AngularJS 双向数据绑定很 Cool 。简单地说,Angular 在 scope 模型上设置了一个监听队列,用来监听数据变化并更新 view 。每次绑定一个东西到 View 上时 AngularJS 就会往 $watch 队列里插入一条 $watch ,用来检测它监听的 Model 里是否有变化的东西。当浏览器接收到可以被 Angular 执行环境处理的事件时,就会触发 $digest 循环,遍历所有的 $watch,Model 稳定后结束循环。大多数时候,浏览器速度很快这个过程不长,这不是一个大问题。但如果在很复杂的应用下使用不当会造成性能问题,比如说表格树组件中滥用双向数据绑定很容易造成界面很卡。

angular-counter.svg

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 中,那么好有两个替代解决方案

感兴趣的话,可以试一试,它们可以很好地减少你的监听数量。

8

评论 (0)

取消