Skip to content

Commit d439960

Browse files
authored
Revert "Adds restamp mode to dom-repeat."
1 parent 20e82c0 commit d439960

File tree

3 files changed

+95
-166
lines changed

3 files changed

+95
-166
lines changed

lib/elements/dom-repeat.html

Lines changed: 67 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -265,32 +265,6 @@
265265
_targetFrameTime: {
266266
type: Number,
267267
computed: '__computeFrameTime(targetFramerate)'
268-
},
269-
270-
/**
271-
* When `restamp` is true, template instances are never reused with
272-
* different items. Instances mapping to current items are moved
273-
* to their new location, new instances are created for any new
274-
* items, and instances for removed items are discarded. This mode is
275-
* generally more expensive than `restamp: false` as it results in
276-
* more instances to be created and discarded during updates and
277-
* disconnection/reconnection churn. By default, object identity is
278-
* used for mapping instances to items. Set `restampKey` to provide
279-
* key based identity.
280-
*/
281-
restamp: {
282-
type: Boolean
283-
},
284-
285-
/**
286-
* When `restamp: true` is used, `restampKey` can be used to provide
287-
* a path into the item object that serves as a unique key for the
288-
* item, for purposes of mapping instances to items. Instances for
289-
* items with the same key will be reused, while all others will be
290-
* either restamped or discarded.
291-
*/
292-
restampKey: {
293-
type: String
294268
}
295269

296270
}
@@ -305,6 +279,7 @@
305279
super();
306280
this.__instances = [];
307281
this.__limit = Infinity;
282+
this.__pool = [];
308283
this.__renderDebouncer = null;
309284
this.__itemsIdxToInstIdx = {};
310285
this.__chunkCount = null;
@@ -320,9 +295,8 @@
320295
disconnectedCallback() {
321296
super.disconnectedCallback();
322297
this.__isDetached = true;
323-
let instances = this.__instances;
324-
for (let i=0; i<instances.length; i++) {
325-
this.__detachInstance(instances[i]);
298+
for (let i=0; i<this.__instances.length; i++) {
299+
this.__detachInstance(i);
326300
}
327301
}
328302

@@ -331,9 +305,9 @@
331305
// only perform attachment if the element was previously detached.
332306
if (this.__isDetached) {
333307
this.__isDetached = false;
334-
let instances = this.__instances;
335-
for (let i=0; i<instances.length; i++) {
336-
this.__attachInstance(instances[i]);
308+
let parent = this.parentNode;
309+
for (let i=0; i<this.__instances.length; i++) {
310+
this.__attachInstance(i, parent);
337311
}
338312
}
339313
}
@@ -523,35 +497,13 @@
523497
// No template found yet
524498
return;
525499
}
526-
let items = this.items || [];
527-
let inst2items = new Array(items.length);
528-
for (let i=0; i<items.length; i++) {
529-
inst2items[i] = i;
530-
}
531-
// Apply user filter
532-
if (this.__filterFn) {
533-
inst2items = inst2items.filter((i, idx, array) =>
534-
this.__filterFn(items[i], idx, array));
535-
}
536-
// Apply user sort
537-
if (this.__sortFn) {
538-
inst2items.sort((a, b) => this.__sortFn(items[a], items[b]));
539-
}
540-
541-
// items->inst map kept for item path forwarding
542-
const items2inst = this.__itemsIdxToInstIdx = {};
543-
const instances = this.__instances;
544-
const limit = Math.max(Math.min(inst2items.length, this.__limit), 0);
545-
// Generate instances and assign items
546-
if (this.restamp) {
547-
this.__renderRestamp(items, instances, limit, inst2items, items2inst);
548-
} else {
549-
this.__renderRefresh(items, instances, limit, inst2items, items2inst);
550-
}
551-
// Remove any extra instances from previous state
552-
while (this.__instances.length > limit) {
553-
this.__detachAndRemoveInstanceAt(limit);
554-
}
500+
this.__applyFullRefresh();
501+
// Reset the pool
502+
// TODO(kschaaf): Reuse pool across turns and nested templates
503+
// Now that objects/arrays are re-evaluated when set, we can safely
504+
// reuse pooled instances across turns, however we still need to decide
505+
// semantics regarding how long to hold, how many to hold, etc.
506+
this.__pool.length = 0;
555507
// Set rendered item count
556508
this._setRenderedItemCount(this.__instances.length);
557509
// Notify users
@@ -563,90 +515,65 @@
563515
this.__tryRenderChunk();
564516
}
565517

566-
__renderRestamp(items, instances, limit, inst2items, items2inst) {
567-
let keyPath = this.restampKey;
568-
const instCache = new Map();
569-
nextItem: for (let i=0; i<limit; i++) {
570-
let itemIdx = inst2items[i];
571-
let item = items[itemIdx];
572-
let key = keyPath && Polymer.Path.get(item, keyPath) || item;
573-
let inst, instItem;
574-
while ((inst = instances[i])) {
575-
instItem = inst[this.as];
576-
let instKey = keyPath && Polymer.Path.get(instItem, keyPath) || instItem;
577-
if (key === instKey) {
578-
inst._setPendingProperty(this.as, item);
579-
inst._setPendingProperty(this.indexAs, i);
580-
inst._setPendingProperty(this.itemsIndexAs, itemIdx);
581-
inst._flushProperties();
582-
items2inst[itemIdx] = i;
583-
continue nextItem;
584-
}
585-
let cache = instCache.get(instKey);
586-
if (cache) {
587-
cache.push(inst);
588-
} else {
589-
instCache.set(instKey, [inst]);
590-
}
591-
instances.splice(i, 1);
592-
}
593-
let cache = instCache.get(key);
594-
if (cache && (inst = cache.shift())) {
595-
this.__reuseInstance(inst, item, i, itemIdx);
596-
if (!cache.length) {
597-
instCache.delete(key);
598-
}
599-
} else {
600-
this.__insertInstance(item, i, itemIdx);
601-
}
602-
items2inst[itemIdx] = i;
518+
__applyFullRefresh() {
519+
let items = this.items || [];
520+
let isntIdxToItemsIdx = new Array(items.length);
521+
for (let i=0; i<items.length; i++) {
522+
isntIdxToItemsIdx[i] = i;
603523
}
604-
instCache.forEach(cache => cache.forEach(inst => this.__detachInstance(inst)));
605-
}
606-
607-
__renderRefresh(items, instances, limit, inst2items, items2inst) {
608-
for (let i=0; i<limit; i++) {
609-
let inst = instances[i];
610-
let itemIdx = inst2items[i];
524+
// Apply user filter
525+
if (this.__filterFn) {
526+
isntIdxToItemsIdx = isntIdxToItemsIdx.filter((i, idx, array) =>
527+
this.__filterFn(items[i], idx, array));
528+
}
529+
// Apply user sort
530+
if (this.__sortFn) {
531+
isntIdxToItemsIdx.sort((a, b) => this.__sortFn(items[a], items[b]));
532+
}
533+
// items->inst map kept for item path forwarding
534+
const itemsIdxToInstIdx = this.__itemsIdxToInstIdx = {};
535+
let instIdx = 0;
536+
// Generate instances and assign items
537+
const limit = Math.min(isntIdxToItemsIdx.length, this.__limit);
538+
for (; instIdx<limit; instIdx++) {
539+
let inst = this.__instances[instIdx];
540+
let itemIdx = isntIdxToItemsIdx[instIdx];
611541
let item = items[itemIdx];
612-
if (inst) {
542+
itemsIdxToInstIdx[itemIdx] = instIdx;
543+
if (inst && instIdx < this.__limit) {
613544
inst._setPendingProperty(this.as, item);
614-
inst._setPendingProperty(this.indexAs, i);
545+
inst._setPendingProperty(this.indexAs, instIdx);
615546
inst._setPendingProperty(this.itemsIndexAs, itemIdx);
616547
inst._flushProperties();
617548
} else {
618-
this.__insertInstance(item, i, itemIdx);
549+
this.__insertInstance(item, instIdx, itemIdx);
619550
}
620-
items2inst[itemIdx] = i;
551+
}
552+
// Remove any extra instances from previous state
553+
for (let i=this.__instances.length-1; i>=instIdx; i--) {
554+
this.__detachAndRemoveInstance(i);
621555
}
622556
}
623557

624-
__detachInstance(inst) {
558+
__detachInstance(idx) {
559+
let inst = this.__instances[idx];
625560
for (let i=0; i<inst.children.length; i++) {
626561
let el = inst.children[i];
627562
inst.root.appendChild(el);
628563
}
564+
return inst;
629565
}
630566

631-
__reuseInstance(inst, item, idx, itemIdx) {
632-
let beforeInst = this.__instances[idx];
633-
let beforeNode = beforeInst ? beforeInst.children[0] : this;
634-
for (let i=0; i<inst.children.length; i++) {
635-
this.parentNode.insertBefore(inst.children[i], beforeNode);
636-
}
637-
this.__instances.splice(idx, 0, inst);
638-
inst._setPendingProperty(this.as, item);
639-
inst._setPendingProperty(this.indexAs, idx);
640-
inst._setPendingProperty(this.itemsIndexAs, itemIdx);
641-
inst._flushProperties();
642-
}
643-
644-
__attachInstance(inst) {
645-
this.parentNode.insertBefore(inst.root, this);
567+
__attachInstance(idx, parent) {
568+
let inst = this.__instances[idx];
569+
parent.insertBefore(inst.root, this);
646570
}
647571

648-
__detachAndRemoveInstanceAt(idx) {
649-
this.__detachInstance(this.__instances[idx]);
572+
__detachAndRemoveInstance(idx) {
573+
let inst = this.__detachInstance(idx);
574+
if (inst) {
575+
this.__pool.push(inst);
576+
}
650577
this.__instances.splice(idx, 1);
651578
}
652579

@@ -659,11 +586,21 @@
659586
}
660587

661588
__insertInstance(item, instIdx, itemIdx) {
662-
let inst = this.__stampInstance(item, instIdx, itemIdx);
663-
let beforeRow = this.__instances[instIdx];
589+
let inst = this.__pool.pop();
590+
if (inst) {
591+
// TODO(kschaaf): If the pool is shared across turns, hostProps
592+
// need to be re-set to reused instances in addition to item
593+
inst._setPendingProperty(this.as, item);
594+
inst._setPendingProperty(this.indexAs, instIdx);
595+
inst._setPendingProperty(this.itemsIndexAs, itemIdx);
596+
inst._flushProperties();
597+
} else {
598+
inst = this.__stampInstance(item, instIdx, itemIdx);
599+
}
600+
let beforeRow = this.__instances[instIdx + 1];
664601
let beforeNode = beforeRow ? beforeRow.children[0] : this;
665602
this.parentNode.insertBefore(inst.root, beforeNode);
666-
this.__instances.splice(instIdx, 0, inst);
603+
this.__instances[instIdx] = inst;
667604
return inst;
668605
}
669606

test/runner.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@
6060
'unit/path.html',
6161
'unit/templatize.html',
6262
'unit/dom-repeat.html',
63-
'unit/dom-repeat.html?restamp',
6463
'unit/dom-if.html',
6564
'unit/dom-bind.html',
6665
'unit/array-selector.html',

0 commit comments

Comments
 (0)