diff options
| author | Karl Seamon | 2013-12-10 17:50:30 -0500 | 
|---|---|---|
| committer | Igor Minar | 2013-12-27 23:31:00 -0800 | 
| commit | 80e7a4558490f7ffd33d142844b9153a5ed00e86 (patch) | |
| tree | a697bc0c7a440a86084dc1024f917ced98986066 /src | |
| parent | 498365f219f65d6c29bdf2f03610a4d3646009bb (diff) | |
| download | angular.js-80e7a4558490f7ffd33d142844b9153a5ed00e86.tar.bz2 | |
perf(Scope): limit propagation of $broadcast to scopes that have listeners for the event
Update $on and $destroy to maintain a count of event keys registered for each scope and its children.
$broadcast will not descend past a node that has a count of 0/undefined for the $broadcasted event key.
Closes #5341
Closes #5371
Diffstat (limited to 'src')
| -rw-r--r-- | src/ng/rootScope.js | 33 | 
1 files changed, 29 insertions, 4 deletions
| diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index a56abc5c..1bb12869 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -133,6 +133,7 @@ function $RootScopeProvider(){        this.$$asyncQueue = [];        this.$$postDigestQueue = [];        this.$$listeners = {}; +      this.$$listenerCount = {};        this.$$isolateBindings = {};      } @@ -192,6 +193,7 @@ function $RootScopeProvider(){          }          child['this'] = child;          child.$$listeners = {}; +        child.$$listenerCount = {};          child.$parent = this;          child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;          child.$$prevSibling = this.$$childTail; @@ -696,6 +698,8 @@ function $RootScopeProvider(){          this.$$destroyed = true;          if (this === $rootScope) return; +        forEach(this.$$listenerCount, bind(null, decrementListenerCount, this)); +          if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;          if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;          if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling; @@ -885,8 +889,18 @@ function $RootScopeProvider(){          }          namedListeners.push(listener); +        var current = this; +        do { +          if (!current.$$listenerCount[name]) { +            current.$$listenerCount[name] = 0; +          } +          current.$$listenerCount[name]++; +        } while ((current = current.$parent)); + +        var self = this;          return function() {            namedListeners[indexOf(namedListeners, listener)] = null; +          decrementListenerCount(self, 1, name);          };        }, @@ -998,8 +1012,7 @@ function $RootScopeProvider(){              listeners, i, length;          //down while you can, then up and next sibling or up and next sibling until back at root -        do { -          current = next; +        while ((current = next)) {            event.currentScope = current;            listeners = current.$$listeners[name] || [];            for (i=0, length = listeners.length; i<length; i++) { @@ -1021,12 +1034,14 @@ function $RootScopeProvider(){            // Insanity Warning: scope depth-first traversal            // yes, this code is a bit crazy, but it works and we have tests to prove it!            // this piece should be kept in sync with the traversal in $digest -          if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) { +          // (though it differs due to having the extra check for $$listenerCount) +          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) || +              (current !== target && current.$$nextSibling)))) {              while(current !== target && !(next = current.$$nextSibling)) {                current = current.$parent;              }            } -        } while ((current = next)); +        }          return event;        } @@ -1055,6 +1070,16 @@ function $RootScopeProvider(){        return fn;      } +    function decrementListenerCount(current, count, name) { +      do { +        current.$$listenerCount[name] -= count; + +        if (current.$$listenerCount[name] === 0) { +          delete current.$$listenerCount[name]; +        } +      } while ((current = current.$parent)); +    } +      /**       * function used as an initial value for watchers.       * because it's unique we can easily tell it apart from other values | 
