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

Commit 7a98172

Browse files
committed
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.
1 parent 263be6b commit 7a98172

File tree

1 file changed

+21
-26
lines changed

1 file changed

+21
-26
lines changed

Diff for: src/ng/directive/ngRepeat.js

+21-26
Original file line numberDiff line numberDiff line change
@@ -425,16 +425,17 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
425425
//watch props
426426
$scope.$watchCollection(rhs, function ngRepeatAction(collection) {
427427
var
428-
block, // last object information {scope, element, id}
429-
collectionKey,
428+
block, // last object information {scope, element, id}
429+
collectionIsLikeArray,
430430
collectionKeys = [],
431431
elementsToRemove,
432-
index, key, value, // key/value of iteration
432+
index, key, value,
433433
lastBlockOrder = [],
434434
lastKey,
435435
nextBlockMap = createMap(),
436436
nextBlockOrder = [],
437-
nextKey, nextLength,
437+
nextKey,
438+
nextLength,
438439
previousNode = $element[0], // node that cloned nodes should be inserted after
439440
// initialized to the comment node anchor
440441
trackById,
@@ -445,23 +446,23 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
445446
}
446447

447448
// get collectionKeys
448-
if (isArrayLike(collection)) {
449-
collectionKeys = collection;
449+
collectionIsLikeArray = isArrayLike(collection);
450+
if (collectionIsLikeArray) {
450451
trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
451452
} else {
452453
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
453454
// if object, extract keys, in enumeration order, unsorted
454-
for (collectionKey in collection) {
455-
if (hasOwnProperty.call(collection, collectionKey) && collectionKey.charAt(0) !== '$') {
456-
collectionKeys.push(collectionKey);
455+
for (key in collection) {
456+
if (hasOwnProperty.call(collection, key) && key.charAt(0) !== '$') {
457+
collectionKeys.push(key);
457458
}
458459
}
459460
}
460-
nextLength = collectionKeys.length;
461+
nextLength = collectionIsLikeArray ? collection.length : collectionKeys.length;
461462

462463
// setup nextBlockMap
463464
for (index = 0; index < nextLength; index++) {
464-
key = (collection === collectionKeys) ? index : collectionKeys[index];
465+
key = collectionIsLikeArray ? index : collectionKeys[index];
465466
value = collection[key];
466467
trackById = trackByIdFn(key, value, index);
467468

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

475-
nextBlockMap[trackById] = {id: trackById, clone: undefined, scope: undefined, index: index, key: key, value: value};
476+
nextBlockMap[trackById] = {id: trackById, clone: undefined, scope: undefined, index: index};
476477
nextBlockOrder[index] = trackById;
477478
}
478479

479480
// setup lastBlockOrder, used to determine if block moved
480-
for (lastKey in lastBlockMap) {
481-
lastBlockOrder.push(lastKey);
481+
for (key in lastBlockMap) {
482+
lastBlockOrder.push(key);
482483
}
483484

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

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

504-
updateScope(block.scope, index,
505-
valueIdentifier, nextBlockMap[nextKey].value,
506-
keyIdentifier, nextBlockMap[nextKey].key, nextLength);
506+
updateScope(block.scope, index, valueIdentifier, collection[key], keyIdentifier, key, nextLength);
507507

508508
nextBlockMap[nextKey] = block;
509509
previousNode = getBlockEnd(block);
@@ -524,24 +524,19 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
524524
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
525525
// by a directive with templateUrl when its template arrives.
526526
nextBlockMap[nextKey].clone = clone;
527-
updateScope(scope, nextBlockMap[nextKey].index,
528-
valueIdentifier, nextBlockMap[nextKey].value,
529-
keyIdentifier, nextBlockMap[nextKey].key, nextLength);
530-
531-
delete nextBlockMap[nextKey].key;
532-
delete nextBlockMap[nextKey].value;
527+
updateScope(scope, nextBlockMap[nextKey].index, valueIdentifier, collection[key], keyIdentifier, key, nextLength);
533528
});
534529
}
535530
}
536531

537532
// leave
538533
// This must go after enter and move because leave prevents getting element's parent.
539-
for (lastKey in lastBlockMap) {
540-
if (nextBlockMap[lastKey]) {
534+
for (key in lastBlockMap) {
535+
if (nextBlockMap[key]) {
541536
continue;
542537
}
543538

544-
block = lastBlockMap[lastKey];
539+
block = lastBlockMap[key];
545540
elementsToRemove = getBlockNodes(block.clone);
546541
$animate.leave(elementsToRemove);
547542
block.scope.$destroy();

0 commit comments

Comments
 (0)