Skip to content
This repository was archived by the owner on Jun 15, 2022. It is now read-only.

Commit 60adca7

Browse files
authored
Revert "amp-list: Fix Bind.rescan vs. diffing race condition (ampproject#32650)" (ampproject#33232)
This reverts commit a0f71df.
1 parent 4e459d0 commit 60adca7

File tree

2 files changed

+13
-89
lines changed

2 files changed

+13
-89
lines changed

extensions/amp-list/0.1/amp-list.js

+13-45
Original file line numberDiff line numberDiff line change
@@ -1095,19 +1095,21 @@ export class AmpList extends AMP.BaseElement {
10951095

10961096
// binding=refresh: Only do render-blocking update after initial render.
10971097
if (binding && binding.startsWith('refresh')) {
1098-
// Don't bother using bindForDocOrNull() since the Bind service must be available after first mutate.
1099-
const afterFirstMutate =
1100-
this.bind_ && this.bind_.signals().get('FIRST_MUTATE');
1101-
if (afterFirstMutate) {
1098+
// Bind service must be available after first mutation, so don't
1099+
// wait on the async service getter.
1100+
if (this.bind_ && this.bind_.signals().get('FIRST_MUTATE')) {
11021101
return updateWith(this.bind_);
11031102
} else {
1104-
// This must be initial render, so do a non-blocking scan for bindings only.
1105-
// [diffable] is a special case that is handled later in render_(), see comment there.
1106-
if (!this.element.hasAttribute('diffable')) {
1107-
this.scanForBindings_(elements, []);
1108-
}
1109-
1110-
// Don't block render and return synchronously.
1103+
// On initial render, do a non-blocking scan and don't update.
1104+
Services.bindForDocOrNull(this.element).then((bind) => {
1105+
if (bind) {
1106+
const evaluate = binding == 'refresh-evaluate';
1107+
bind.rescan(elements, [], {
1108+
'fast': true,
1109+
'update': evaluate ? 'evaluate' : false,
1110+
});
1111+
}
1112+
});
11111113
return Promise.resolve(elements);
11121114
}
11131115
}
@@ -1122,32 +1124,6 @@ export class AmpList extends AMP.BaseElement {
11221124
});
11231125
}
11241126

1125-
/**
1126-
* Scans for bindings in `addedElements` and removes bindings in `removedElements`.
1127-
* Unlike updateBindings(), does NOT apply bindings or update DOM.
1128-
* Should only be used for binding="refresh" or binding="refresh-evaluate".
1129-
* @param {!Array<!Element>} addedElements
1130-
* @param {!Array<!Element>} removedElements
1131-
* @private
1132-
*/
1133-
scanForBindings_(addedElements, removedElements) {
1134-
const binding = this.element.getAttribute('binding');
1135-
if (!binding || !binding.startsWith('refresh')) {
1136-
return;
1137-
}
1138-
Services.bindForDocOrNull(this.element).then((bind) => {
1139-
if (bind) {
1140-
// For binding="refresh-evaluate", we scan for bindings, evaluate+cache expressions, but skip DOM update.
1141-
// For binding="refresh", we only scan for bindings.
1142-
const update = binding == 'refresh-evaluate' ? 'evaluate' : false;
1143-
bind.rescan(addedElements, removedElements, {
1144-
'fast': true,
1145-
'update': update,
1146-
});
1147-
}
1148-
});
1149-
}
1150-
11511127
/**
11521128
* @param {!Array<!Element>} elements
11531129
* @param {boolean=} opt_append
@@ -1164,14 +1140,6 @@ export class AmpList extends AMP.BaseElement {
11641140
// TODO:(wg-performance)(#28781) Ensure owners_.scheduleUnlayout() is
11651141
// called for diff elements that are removed
11661142
this.diff_(container, elements);
1167-
1168-
// For diffable amp-list, we have to wait until DOM diffing is done here to scan for new bindings
1169-
// (vs. asynchronously in updateBindings()), and scan the entire container (vs. just `elements`).
1170-
//
1171-
// This is because instead of replacing the entire DOM subtree, the diffing process removes
1172-
// select children from `elements` and inserts them into the container. This results in a race
1173-
// between diff_() and Bind.rescan(), which we avoid by delaying the latter until now.
1174-
this.scanForBindings_([container], [container]);
11751143
} else {
11761144
if (!opt_append) {
11771145
this.owners_./*OK*/ scheduleUnlayout(this.element, container);

extensions/amp-list/0.1/test/test-amp-list.js

-44
Original file line numberDiff line numberDiff line change
@@ -1413,50 +1413,6 @@ describes.repeated(
14131413
}
14141414
);
14151415
});
1416-
1417-
describe('rescan vs. diff race', () => {
1418-
async function rescanVsDiffTest() {
1419-
env.sandbox.spy(list, 'diff_');
1420-
env.sandbox.spy(list, 'render_');
1421-
1422-
// Diffing is skipped if there's no existing children to diff against.
1423-
const oldChild = doc.createElement('p');
1424-
oldChild.textContent = 'foo';
1425-
list.container_.appendChild(oldChild);
1426-
1427-
const newChild = doc.createElement('p');
1428-
newChild.textContent = 'bar';
1429-
// New children must have at least one binding to trigger rescan.
1430-
newChild.setAttribute('i-amphtml-binding', '');
1431-
const rendered = expectFetchAndRender(DEFAULT_FETCHED_DATA, [
1432-
newChild,
1433-
]);
1434-
await list.layoutCallback().then(() => rendered);
1435-
}
1436-
1437-
it('without diffing, should rescan _before_ render', async () => {
1438-
await rescanVsDiffTest();
1439-
1440-
expect(list.diff_).to.not.have.been.called;
1441-
expect(bind.rescan).to.have.been.calledOnce;
1442-
1443-
// Without diffable, rescan should happen before rendering the new children.
1444-
expect(bind.rescan).calledBefore(list.render_);
1445-
});
1446-
1447-
it('with diffing, should rescan _after_ render/diff', async () => {
1448-
element.setAttribute('diffable', '');
1449-
1450-
await rescanVsDiffTest();
1451-
1452-
expect(list.diff_).to.have.been.calledOnce;
1453-
expect(bind.rescan).to.have.been.calledOnce;
1454-
1455-
// With diffable, rescanning must happen after rendering (diffing) the new children.
1456-
expect(bind.rescan).calledAfter(list.render_);
1457-
expect(bind.rescan).calledAfter(list.diff_);
1458-
});
1459-
});
14601416
});
14611417

14621418
describe('binding="no"', () => {

0 commit comments

Comments
 (0)