From bb366d1feff4297dd3057280396182a9d4a9a772 Mon Sep 17 00:00:00 2001 From: Daniel Herman Date: Thu, 28 Jan 2016 17:54:20 -0500 Subject: [PATCH 1/3] perf(ngRepeat): avoid duplicate jqLite wrappers Internally, `$animate` already wraps elements passed through with `jqLite`, so we can avoid needless duplication here. --- src/ng/directive/ngRepeat.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ng/directive/ngRepeat.js b/src/ng/directive/ngRepeat.js index 76e589dba182..27eff176360f 100644 --- a/src/ng/directive/ngRepeat.js +++ b/src/ng/directive/ngRepeat.js @@ -515,7 +515,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { if (getBlockStart(block) != nextNode) { // existing item which got moved - $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode)); + $animate.move(getBlockNodes(block.clone), null, previousNode); } previousNode = getBlockEnd(block); updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength); @@ -527,8 +527,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { var endNode = ngRepeatEndComment.cloneNode(false); clone[clone.length++] = endNode; - // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper? - $animate.enter(clone, null, jqLite(previousNode)); + $animate.enter(clone, null, previousNode); previousNode = endNode; // Note: We only need the first/last node of the cloned nodes. // However, we need to keep the reference to the jqlite wrapper as it might be changed later From 81ae59b3651f84f903f20118f027df5ce2532c0a Mon Sep 17 00:00:00 2001 From: Daniel Herman Date: Thu, 28 Jan 2016 17:55:25 -0500 Subject: [PATCH 2/3] perf(ngAnimate): avoid $.fn.data overhead with jQuery Unlike jqLite, jquery scrapes the attributes of an element looking for data- keys that match the requested property. When many elements are being animated due to something like `ngRepeat` unrolling within one digest cycle, the amount of time spent in that one function quickly adds up. By changing our API to use the lower level data API, we can cut the time spent in this function by half when jQuery is loaded. --- src/ngAnimate/animateQueue.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngAnimate/animateQueue.js b/src/ngAnimate/animateQueue.js index 7f4da4bdc4b9..9eec04cc598c 100644 --- a/src/ngAnimate/animateQueue.js +++ b/src/ngAnimate/animateQueue.js @@ -585,7 +585,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { var animateChildren; var elementDisabled = disabledElementsLookup.get(getDomNode(element)); - var parentHost = element.data(NG_ANIMATE_PIN_DATA); + var parentHost = jqLite.data(element[0], NG_ANIMATE_PIN_DATA); if (parentHost) { parentElement = parentHost; } @@ -623,7 +623,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { } if (isUndefined(animateChildren) || animateChildren === true) { - var value = parentElement.data(NG_ANIMATE_CHILDREN_DATA); + var value = jqLite.data(parentElement[0], NG_ANIMATE_CHILDREN_DATA); if (isDefined(value)) { animateChildren = value; } @@ -646,7 +646,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { if (!rootElementDetected) { // If no rootElement is detected, check if the parentElement is pinned to another element - parentHost = parentElement.data(NG_ANIMATE_PIN_DATA); + parentHost = jqLite.data(parentElement[0], NG_ANIMATE_PIN_DATA); if (parentHost) { // The pin target element becomes the next parent element parentElement = parentHost; From 29f1eacbf13fbf540105e703ad098f99e59f08e7 Mon Sep 17 00:00:00 2001 From: Daniel Herman Date: Tue, 9 Feb 2016 09:38:30 -0500 Subject: [PATCH 3/3] perf(ngAnimate): avoid jqLite/jQuery for upward DOM traversal The `parentNode` property is well supported between all browsers. Since no other functionality was required here other than traversing upwards using `.parent()`, we can use the DOM API directly. --- src/ngAnimate/animateQueue.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/ngAnimate/animateQueue.js b/src/ngAnimate/animateQueue.js index 9eec04cc598c..146e538a1508 100644 --- a/src/ngAnimate/animateQueue.js +++ b/src/ngAnimate/animateQueue.js @@ -590,25 +590,26 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { parentElement = parentHost; } - while (parentElement && parentElement.length) { + parentElement = getDomNode(parentElement); + + while (parentElement) { if (!rootElementDetected) { // angular doesn't want to attempt to animate elements outside of the application // therefore we need to ensure that the rootElement is an ancestor of the current element rootElementDetected = isMatchingElement(parentElement, $rootElement); } - var parentNode = parentElement[0]; - if (parentNode.nodeType !== ELEMENT_NODE) { + if (parentElement.nodeType !== ELEMENT_NODE) { // no point in inspecting the #document element break; } - var details = activeAnimationsLookup.get(parentNode) || {}; + var details = activeAnimationsLookup.get(parentElement) || {}; // either an enter, leave or move animation will commence // therefore we can't allow any animations to take place // but if a parent animation is class-based then that's ok if (!parentAnimationDetected) { - var parentElementDisabled = disabledElementsLookup.get(parentNode); + var parentElementDisabled = disabledElementsLookup.get(parentElement); if (parentElementDisabled === true && elementDisabled !== false) { // disable animations if the user hasn't explicitly enabled animations on the @@ -623,7 +624,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { } if (isUndefined(animateChildren) || animateChildren === true) { - var value = jqLite.data(parentElement[0], NG_ANIMATE_CHILDREN_DATA); + var value = jqLite.data(parentElement, NG_ANIMATE_CHILDREN_DATA); if (isDefined(value)) { animateChildren = value; } @@ -646,15 +647,15 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { if (!rootElementDetected) { // If no rootElement is detected, check if the parentElement is pinned to another element - parentHost = jqLite.data(parentElement[0], NG_ANIMATE_PIN_DATA); + parentHost = jqLite.data(parentElement, NG_ANIMATE_PIN_DATA); if (parentHost) { // The pin target element becomes the next parent element - parentElement = parentHost; + parentElement = getDomNode(parentHost); continue; } } - parentElement = parentElement.parent(); + parentElement = parentElement.parentNode; } var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true;