Unable to reduce the number of watchers in ng-repe

2019-04-10 01:56发布

In a performance purpose, i wanted to remove the double data-binding (so, the associated watchers) from my ng-repeat.

It loads 30 items, and those data are static once loaded, so no need for double data binding.

The thing is that the watcher amount remains the same on that page, no matter how i do it.

Let say :


<div ng-repeat='stuff in stuffs'>
   // nothing in here
</div>

Watchers amount is 211 (there is other binding on that page, not only ng-repeat)


<div ng-repeat='stuff in ::stuffs'>
   // nothing in here
</div>

Watchers amount is still 211 ( it should be 210 if i understand it right), but wait :


<div ng-repeat='stuff in ::stuffs'>
    {{stuff.id}}
</div>

Watchers amount is now 241 (well ok, 211 watchers + 30 stuffs * 1 watcher = 241 watchers)


<div ng-repeat='stuff in ::stuffs'>
    {{::stuff.id}}
</div>

Watchers amount is still 241 !!! Is :: not supposed to remove associated watcher ??


<div ng-repeat='stuff in ::stuffs'>
    {{stuff.id}}  {{stuff.name}}  {{stuff.desc}}
</div>

Still 241...


Those exemples has really been made in my app, so those numbers are real too.

The real ng-repeat is far more complex than the exemple one here, and i reach ~1500 watchers on my page. If i delete its content ( like in the exemple), i fall down to ~200 watchers. So how can i optimize it ? Why :: does't seem to work ?

Thank you to enlighten me...

1条回答
聊天终结者
2楼-- · 2019-04-10 02:37

It's hard to figure out what's the exact problem in your specific case, maybe it makes sense to provide an isolated example, so that other guys can help.

The result might depend on how you count the watchers. I took solution from here.

Here is a Plunker example working as expected (add or remove :: in ng-repeat):

HTML

<!DOCTYPE html>
<html ng-app="app">
  <head>
    <script data-require="angular.js@1.5.6" data-semver="1.5.6" src="https://code.angularjs.org/1.5.6/angular.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>
  <body ng-controller="mainCtrl">
    <div>{{name}}</div>

    <ul>
      <li ng-repeat="item in ::items">{{::item.id}} - {{::item.name}}</li>
    </ul>

    <button id="watchersCountBtn">Show watchers count</button>
    <div id="watchersCountLog"></div>
  </body>
</html>

JavaScript

angular
  .module('app', [])
  .controller('mainCtrl', function($scope) {
    $scope.name = 'Hello World';

    $scope.items = [
      { id: 1, name: 'product 1' },
      { id: 2, name: 'product 2' },
      { id: 3, name: 'product 3' },
      { id: 4, name: 'product 4' },
      { id: 5, name: 'product 5' },
      { id: 6, name: 'product 6' },
      { id: 7, name: 'product 7' },
      { id: 8, name: 'product 8' },
      { id: 9, name: 'product 9' },
      { id: 10, name: 'product 10' }
    ];
  });

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);
}

window.onload = function() {
  var btn = document.getElementById('watchersCountBtn');
  var log = document.getElementById('watchersCountLog');

  window.addEventListener('click', function() {
    log.innerText = getWatchers().length;
  });
};

Hope this helps.

查看更多
登录 后发表回答