Skip to content

Commit

Permalink
Merge pull request #4785 from Polymer/revert-4363-1713-kschaaf-repeat…
Browse files Browse the repository at this point in the history
…-restamp

Revert "Adds `restamp` mode to dom-repeat."
  • Loading branch information
dfreedm authored Aug 10, 2017
2 parents 20e82c0 + d439960 commit ee3d36f
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 166 deletions.
197 changes: 67 additions & 130 deletions lib/elements/dom-repeat.html
Original file line number Diff line number Diff line change
Expand Up @@ -265,32 +265,6 @@
_targetFrameTime: {
type: Number,
computed: '__computeFrameTime(targetFramerate)'
},

/**
* When `restamp` is true, template instances are never reused with
* different items. Instances mapping to current items are moved
* to their new location, new instances are created for any new
* items, and instances for removed items are discarded. This mode is
* generally more expensive than `restamp: false` as it results in
* more instances to be created and discarded during updates and
* disconnection/reconnection churn. By default, object identity is
* used for mapping instances to items. Set `restampKey` to provide
* key based identity.
*/
restamp: {
type: Boolean
},

/**
* When `restamp: true` is used, `restampKey` can be used to provide
* a path into the item object that serves as a unique key for the
* item, for purposes of mapping instances to items. Instances for
* items with the same key will be reused, while all others will be
* either restamped or discarded.
*/
restampKey: {
type: String
}

}
Expand All @@ -305,6 +279,7 @@
super();
this.__instances = [];
this.__limit = Infinity;
this.__pool = [];
this.__renderDebouncer = null;
this.__itemsIdxToInstIdx = {};
this.__chunkCount = null;
Expand All @@ -320,9 +295,8 @@
disconnectedCallback() {
super.disconnectedCallback();
this.__isDetached = true;
let instances = this.__instances;
for (let i=0; i<instances.length; i++) {
this.__detachInstance(instances[i]);
for (let i=0; i<this.__instances.length; i++) {
this.__detachInstance(i);
}
}

Expand All @@ -331,9 +305,9 @@
// only perform attachment if the element was previously detached.
if (this.__isDetached) {
this.__isDetached = false;
let instances = this.__instances;
for (let i=0; i<instances.length; i++) {
this.__attachInstance(instances[i]);
let parent = this.parentNode;
for (let i=0; i<this.__instances.length; i++) {
this.__attachInstance(i, parent);
}
}
}
Expand Down Expand Up @@ -523,35 +497,13 @@
// No template found yet
return;
}
let items = this.items || [];
let inst2items = new Array(items.length);
for (let i=0; i<items.length; i++) {
inst2items[i] = i;
}
// Apply user filter
if (this.__filterFn) {
inst2items = inst2items.filter((i, idx, array) =>
this.__filterFn(items[i], idx, array));
}
// Apply user sort
if (this.__sortFn) {
inst2items.sort((a, b) => this.__sortFn(items[a], items[b]));
}

// items->inst map kept for item path forwarding
const items2inst = this.__itemsIdxToInstIdx = {};
const instances = this.__instances;
const limit = Math.max(Math.min(inst2items.length, this.__limit), 0);
// Generate instances and assign items
if (this.restamp) {
this.__renderRestamp(items, instances, limit, inst2items, items2inst);
} else {
this.__renderRefresh(items, instances, limit, inst2items, items2inst);
}
// Remove any extra instances from previous state
while (this.__instances.length > limit) {
this.__detachAndRemoveInstanceAt(limit);
}
this.__applyFullRefresh();
// Reset the pool
// TODO(kschaaf): Reuse pool across turns and nested templates
// Now that objects/arrays are re-evaluated when set, we can safely
// reuse pooled instances across turns, however we still need to decide
// semantics regarding how long to hold, how many to hold, etc.
this.__pool.length = 0;
// Set rendered item count
this._setRenderedItemCount(this.__instances.length);
// Notify users
Expand All @@ -563,90 +515,65 @@
this.__tryRenderChunk();
}

__renderRestamp(items, instances, limit, inst2items, items2inst) {
let keyPath = this.restampKey;
const instCache = new Map();
nextItem: for (let i=0; i<limit; i++) {
let itemIdx = inst2items[i];
let item = items[itemIdx];
let key = keyPath && Polymer.Path.get(item, keyPath) || item;
let inst, instItem;
while ((inst = instances[i])) {
instItem = inst[this.as];
let instKey = keyPath && Polymer.Path.get(instItem, keyPath) || instItem;
if (key === instKey) {
inst._setPendingProperty(this.as, item);
inst._setPendingProperty(this.indexAs, i);
inst._setPendingProperty(this.itemsIndexAs, itemIdx);
inst._flushProperties();
items2inst[itemIdx] = i;
continue nextItem;
}
let cache = instCache.get(instKey);
if (cache) {
cache.push(inst);
} else {
instCache.set(instKey, [inst]);
}
instances.splice(i, 1);
}
let cache = instCache.get(key);
if (cache && (inst = cache.shift())) {
this.__reuseInstance(inst, item, i, itemIdx);
if (!cache.length) {
instCache.delete(key);
}
} else {
this.__insertInstance(item, i, itemIdx);
}
items2inst[itemIdx] = i;
__applyFullRefresh() {
let items = this.items || [];
let isntIdxToItemsIdx = new Array(items.length);
for (let i=0; i<items.length; i++) {
isntIdxToItemsIdx[i] = i;
}
instCache.forEach(cache => cache.forEach(inst => this.__detachInstance(inst)));
}

__renderRefresh(items, instances, limit, inst2items, items2inst) {
for (let i=0; i<limit; i++) {
let inst = instances[i];
let itemIdx = inst2items[i];
// Apply user filter
if (this.__filterFn) {
isntIdxToItemsIdx = isntIdxToItemsIdx.filter((i, idx, array) =>
this.__filterFn(items[i], idx, array));
}
// Apply user sort
if (this.__sortFn) {
isntIdxToItemsIdx.sort((a, b) => this.__sortFn(items[a], items[b]));
}
// items->inst map kept for item path forwarding
const itemsIdxToInstIdx = this.__itemsIdxToInstIdx = {};
let instIdx = 0;
// Generate instances and assign items
const limit = Math.min(isntIdxToItemsIdx.length, this.__limit);
for (; instIdx<limit; instIdx++) {
let inst = this.__instances[instIdx];
let itemIdx = isntIdxToItemsIdx[instIdx];
let item = items[itemIdx];
if (inst) {
itemsIdxToInstIdx[itemIdx] = instIdx;
if (inst && instIdx < this.__limit) {
inst._setPendingProperty(this.as, item);
inst._setPendingProperty(this.indexAs, i);
inst._setPendingProperty(this.indexAs, instIdx);
inst._setPendingProperty(this.itemsIndexAs, itemIdx);
inst._flushProperties();
} else {
this.__insertInstance(item, i, itemIdx);
this.__insertInstance(item, instIdx, itemIdx);
}
items2inst[itemIdx] = i;
}
// Remove any extra instances from previous state
for (let i=this.__instances.length-1; i>=instIdx; i--) {
this.__detachAndRemoveInstance(i);
}
}

__detachInstance(inst) {
__detachInstance(idx) {
let inst = this.__instances[idx];
for (let i=0; i<inst.children.length; i++) {
let el = inst.children[i];
inst.root.appendChild(el);
}
return inst;
}

__reuseInstance(inst, item, idx, itemIdx) {
let beforeInst = this.__instances[idx];
let beforeNode = beforeInst ? beforeInst.children[0] : this;
for (let i=0; i<inst.children.length; i++) {
this.parentNode.insertBefore(inst.children[i], beforeNode);
}
this.__instances.splice(idx, 0, inst);
inst._setPendingProperty(this.as, item);
inst._setPendingProperty(this.indexAs, idx);
inst._setPendingProperty(this.itemsIndexAs, itemIdx);
inst._flushProperties();
}

__attachInstance(inst) {
this.parentNode.insertBefore(inst.root, this);
__attachInstance(idx, parent) {
let inst = this.__instances[idx];
parent.insertBefore(inst.root, this);
}

__detachAndRemoveInstanceAt(idx) {
this.__detachInstance(this.__instances[idx]);
__detachAndRemoveInstance(idx) {
let inst = this.__detachInstance(idx);
if (inst) {
this.__pool.push(inst);
}
this.__instances.splice(idx, 1);
}

Expand All @@ -659,11 +586,21 @@
}

__insertInstance(item, instIdx, itemIdx) {
let inst = this.__stampInstance(item, instIdx, itemIdx);
let beforeRow = this.__instances[instIdx];
let inst = this.__pool.pop();
if (inst) {
// TODO(kschaaf): If the pool is shared across turns, hostProps
// need to be re-set to reused instances in addition to item
inst._setPendingProperty(this.as, item);
inst._setPendingProperty(this.indexAs, instIdx);
inst._setPendingProperty(this.itemsIndexAs, itemIdx);
inst._flushProperties();
} else {
inst = this.__stampInstance(item, instIdx, itemIdx);
}
let beforeRow = this.__instances[instIdx + 1];
let beforeNode = beforeRow ? beforeRow.children[0] : this;
this.parentNode.insertBefore(inst.root, beforeNode);
this.__instances.splice(instIdx, 0, inst);
this.__instances[instIdx] = inst;
return inst;
}

Expand Down
1 change: 0 additions & 1 deletion test/runner.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
'unit/path.html',
'unit/templatize.html',
'unit/dom-repeat.html',
'unit/dom-repeat.html?restamp',
'unit/dom-if.html',
'unit/dom-bind.html',
'unit/array-selector.html',
Expand Down
Loading

0 comments on commit ee3d36f

Please sign in to comment.