From e4a68fcbf44dfaab9d3eebf174badaa103de57f9 Mon Sep 17 00:00:00 2001 From: Karl Seamon Date: Tue, 10 Dec 2013 17:50:30 -0500 Subject: [PATCH] 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 --- src/ng/rootScope.js | 33 ++++++++-- test/ng/rootScopeSpec.js | 126 +++++++++++++++++++++++++++++++++------ 2 files changed, 136 insertions(+), 23 deletions(-) diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index a56abc5c6784..1bb128695f8d 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