Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
perf(ngRepeat): use less memory and compare less
Browse files Browse the repository at this point in the history
In the ngRepeatAction function:
* The collection keys and values are accessed directly instead of copying them to nextBlockMap temporarily.
* Checking the collectionIsLikeArray boolean value is faster than comparing value and type of collectionKeys and collection.
  • Loading branch information
pondermatic committed Sep 12, 2016
1 parent 263be6b commit 7a98172
Showing 1 changed file with 21 additions and 26 deletions.
47 changes: 21 additions & 26 deletions src/ng/directive/ngRepeat.js
Original file line number Diff line number Diff line change
Expand Up @@ -425,16 +425,17 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
//watch props
$scope.$watchCollection(rhs, function ngRepeatAction(collection) {
var
block, // last object information {scope, element, id}
collectionKey,
block, // last object information {scope, element, id}
collectionIsLikeArray,
collectionKeys = [],
elementsToRemove,
index, key, value, // key/value of iteration
index, key, value,
lastBlockOrder = [],
lastKey,
nextBlockMap = createMap(),
nextBlockOrder = [],
nextKey, nextLength,
nextKey,
nextLength,
previousNode = $element[0], // node that cloned nodes should be inserted after
// initialized to the comment node anchor
trackById,
Expand All @@ -445,23 +446,23 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
}

// get collectionKeys
if (isArrayLike(collection)) {
collectionKeys = collection;
collectionIsLikeArray = isArrayLike(collection);
if (collectionIsLikeArray) {
trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
} else {
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
// if object, extract keys, in enumeration order, unsorted
for (collectionKey in collection) {
if (hasOwnProperty.call(collection, collectionKey) && collectionKey.charAt(0) !== '$') {
collectionKeys.push(collectionKey);
for (key in collection) {
if (hasOwnProperty.call(collection, key) && key.charAt(0) !== '$') {
collectionKeys.push(key);
}
}
}
nextLength = collectionKeys.length;
nextLength = collectionIsLikeArray ? collection.length : collectionKeys.length;

// setup nextBlockMap
for (index = 0; index < nextLength; index++) {
key = (collection === collectionKeys) ? index : collectionKeys[index];
key = collectionIsLikeArray ? index : collectionKeys[index];
value = collection[key];
trackById = trackByIdFn(key, value, index);

Expand All @@ -472,16 +473,17 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
expression, trackById, value);
}

nextBlockMap[trackById] = {id: trackById, clone: undefined, scope: undefined, index: index, key: key, value: value};
nextBlockMap[trackById] = {id: trackById, clone: undefined, scope: undefined, index: index};
nextBlockOrder[index] = trackById;
}

// setup lastBlockOrder, used to determine if block moved
for (lastKey in lastBlockMap) {
lastBlockOrder.push(lastKey);
for (key in lastBlockMap) {
lastBlockOrder.push(key);
}

for (index = 0; index < nextLength; index++) {
key = collectionIsLikeArray ? index : collectionKeys[index];
nextKey = nextBlockOrder[index];

if (lastBlockMap[nextKey]) {
Expand All @@ -501,9 +503,7 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
block.index = nextBlockMap[nextKey].index;
}

updateScope(block.scope, index,
valueIdentifier, nextBlockMap[nextKey].value,
keyIdentifier, nextBlockMap[nextKey].key, nextLength);
updateScope(block.scope, index, valueIdentifier, collection[key], keyIdentifier, key, nextLength);

nextBlockMap[nextKey] = block;
previousNode = getBlockEnd(block);
Expand All @@ -524,24 +524,19 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
// by a directive with templateUrl when its template arrives.
nextBlockMap[nextKey].clone = clone;
updateScope(scope, nextBlockMap[nextKey].index,
valueIdentifier, nextBlockMap[nextKey].value,
keyIdentifier, nextBlockMap[nextKey].key, nextLength);

delete nextBlockMap[nextKey].key;
delete nextBlockMap[nextKey].value;
updateScope(scope, nextBlockMap[nextKey].index, valueIdentifier, collection[key], keyIdentifier, key, nextLength);
});
}
}

// leave
// This must go after enter and move because leave prevents getting element's parent.
for (lastKey in lastBlockMap) {
if (nextBlockMap[lastKey]) {
for (key in lastBlockMap) {
if (nextBlockMap[key]) {
continue;
}

block = lastBlockMap[lastKey];
block = lastBlockMap[key];
elementsToRemove = getBlockNodes(block.clone);
$animate.leave(elementsToRemove);
block.scope.$destroy();
Expand Down

0 comments on commit 7a98172

Please sign in to comment.