Skip to content

Commit fc8ac23

Browse files
pondermaticNarretz
authored andcommitted
perf(ngRepeat): use less memory and compare less
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. Closes angular#15072
1 parent e1b2dd6 commit fc8ac23

File tree

1 file changed

+21
-26
lines changed

1 file changed

+21
-26
lines changed

src/ng/directive/ngRepeat.js

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -433,16 +433,17 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
433433
//watch props
434434
$scope.$watchCollection(rhs, function ngRepeatAction(collection) {
435435
var
436-
block, // last object information {scope, element, id}
437-
collectionKey,
436+
block, // last object information {scope, element, id}
437+
collectionIsLikeArray,
438438
collectionKeys = [],
439439
elementsToRemove,
440-
index, key, value, // key/value of iteration
440+
index, key, value,
441441
lastBlockOrder = [],
442442
lastKey,
443443
nextBlockMap = createMap(),
444444
nextBlockOrder = [],
445-
nextKey, nextLength,
445+
nextKey,
446+
nextLength,
446447
previousNode = $element[0], // node that cloned nodes should be inserted after
447448
// initialized to the comment node anchor
448449
trackById,
@@ -453,23 +454,23 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
453454
}
454455

455456
// get collectionKeys
456-
if (isArrayLike(collection)) {
457-
collectionKeys = collection;
457+
collectionIsLikeArray = isArrayLike(collection);
458+
if (collectionIsLikeArray) {
458459
trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
459460
} else {
460461
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
461462
// if object, extract keys, in enumeration order, unsorted
462-
for (collectionKey in collection) {
463-
if (hasOwnProperty.call(collection, collectionKey) && collectionKey.charAt(0) !== '$') {
464-
collectionKeys.push(collectionKey);
463+
for (key in collection) {
464+
if (hasOwnProperty.call(collection, key) && key.charAt(0) !== '$') {
465+
collectionKeys.push(key);
465466
}
466467
}
467468
}
468-
nextLength = collectionKeys.length;
469+
nextLength = collectionIsLikeArray ? collection.length : collectionKeys.length;
469470

470471
// setup nextBlockMap
471472
for (index = 0; index < nextLength; index++) {
472-
key = (collection === collectionKeys) ? index : collectionKeys[index];
473+
key = collectionIsLikeArray ? index : collectionKeys[index];
473474
value = collection[key];
474475
trackById = trackByIdFn(key, value, index);
475476

@@ -480,16 +481,17 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
480481
expression, trackById, value);
481482
}
482483

483-
nextBlockMap[trackById] = {id: trackById, clone: undefined, scope: undefined, index: index, key: key, value: value};
484+
nextBlockMap[trackById] = {id: trackById, clone: undefined, scope: undefined, index: index};
484485
nextBlockOrder[index] = trackById;
485486
}
486487

487488
// setup lastBlockOrder, used to determine if block moved
488-
for (lastKey in lastBlockMap) {
489-
lastBlockOrder.push(lastKey);
489+
for (key in lastBlockMap) {
490+
lastBlockOrder.push(key);
490491
}
491492

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

495497
if (lastBlockMap[nextKey]) {
@@ -509,9 +511,7 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
509511
block.index = nextBlockMap[nextKey].index;
510512
}
511513

512-
updateScope(block.scope, index,
513-
valueIdentifier, nextBlockMap[nextKey].value,
514-
keyIdentifier, nextBlockMap[nextKey].key, nextLength);
514+
updateScope(block.scope, index, valueIdentifier, collection[key], keyIdentifier, key, nextLength);
515515

516516
nextBlockMap[nextKey] = block;
517517
previousNode = getBlockEnd(block);
@@ -532,24 +532,19 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
532532
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
533533
// by a directive with templateUrl when its template arrives.
534534
nextBlockMap[nextKey].clone = clone;
535-
updateScope(scope, nextBlockMap[nextKey].index,
536-
valueIdentifier, nextBlockMap[nextKey].value,
537-
keyIdentifier, nextBlockMap[nextKey].key, nextLength);
538-
539-
delete nextBlockMap[nextKey].key;
540-
delete nextBlockMap[nextKey].value;
535+
updateScope(scope, nextBlockMap[nextKey].index, valueIdentifier, collection[key], keyIdentifier, key, nextLength);
541536
});
542537
}
543538
}
544539

545540
// leave
546541
// This must go after enter and move because leave prevents getting element's parent.
547-
for (lastKey in lastBlockMap) {
548-
if (nextBlockMap[lastKey]) {
542+
for (key in lastBlockMap) {
543+
if (nextBlockMap[key]) {
549544
continue;
550545
}
551546

552-
block = lastBlockMap[lastKey];
547+
block = lastBlockMap[key];
553548
elementsToRemove = getBlockNodes(block.clone);
554549
$animate.leave(elementsToRemove);
555550
block.scope.$destroy();

0 commit comments

Comments
 (0)