Skip to content

Commit 2a09c5a

Browse files
MichaelWest22botandrose-machine
authored andcommitted
bring back old softMatch behaviour to reduce churn.
1 parent 4ffac5d commit 2a09c5a

File tree

2 files changed

+46
-9
lines changed

2 files changed

+46
-9
lines changed

src/idiomorph.js

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ var Idiomorph = (function () {
373373
/**
374374
* Scans forward from the startPoint to the endPoint looking for a match
375375
* for the node. It looks for an id set match first, then a soft match.
376+
* We abort softmatching if we find two future soft matches, to reduce churn.
376377
* @param {Node} node
377378
* @param {MorphContext} ctx
378379
* @param {Node | null} startPoint
@@ -381,6 +382,8 @@ var Idiomorph = (function () {
381382
*/
382383
function findBestMatch(ctx, node, startPoint, endPoint) {
383384
let softMatch = null;
385+
let nextSibling = node.nextSibling;
386+
let siblingSoftMatchCount = 0;
384387

385388
let cursor = startPoint;
386389
while (cursor && cursor != endPoint) {
@@ -391,23 +394,36 @@ var Idiomorph = (function () {
391394
}
392395

393396
// we haven't yet saved a soft match fallback
394-
if (!softMatch) {
397+
if (softMatch === null) {
395398
// the current soft match will hard match something else in the future, leave it
396399
if (!ctx.idMap.has(cursor)) {
397-
// optimization: if node can't id set match, we can just return the soft match immediately
398-
if (!ctx.idMap.has(node)) {
399-
return cursor;
400-
} else {
401-
// save this as the fallback if we get through the loop without finding a hard match
402-
softMatch = cursor;
403-
}
400+
// save this as the fallback if we get through the loop without finding a hard match
401+
softMatch = cursor;
404402
}
405403
}
406404
}
405+
if (
406+
softMatch === null &&
407+
nextSibling &&
408+
isSoftMatch(cursor, nextSibling)
409+
) {
410+
// The next new node has a soft match with this node, so
411+
// increment the count of future soft matches
412+
siblingSoftMatchCount++;
413+
nextSibling = nextSibling.nextSibling;
414+
415+
// If there are two future soft matches, block soft matching for this node to allow
416+
// future siblings to soft match. This is to reduce churn in the DOM when an element
417+
// is prepended.
418+
if (siblingSoftMatchCount >= 2) {
419+
softMatch = undefined;
420+
}
421+
}
422+
407423
cursor = cursor.nextSibling;
408424
}
409425

410-
return softMatch;
426+
return softMatch || null;
411427
}
412428

413429
/**

test/ops.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,25 @@ describe("morphing operations", function () {
167167
],
168168
);
169169
});
170+
171+
it("show softMatch aborting on two future soft matches", function () {
172+
// when nodes can't be softMatched because they have different types it will scan ahead
173+
// but it aborts the scan ahead if it finds two nodes ahead in both the new and old content
174+
// that softmatch so it can just insert the mis matched node it is on and get to the matching.
175+
assertOps(
176+
"<section><h1></h1><h2></h2><div></div></section>",
177+
"<section><div>Alert</div><h1></h1><h2></h2><div></div></section>",
178+
[
179+
[
180+
"Morphed",
181+
"<section><h1></h1><h2></h2><div></div></section>",
182+
"<section><div>Alert</div><h1></h1><h2></h2><div></div></section>",
183+
],
184+
["Added", "<div>Alert</div>"],
185+
["Morphed", "<h1></h1>", "<h1></h1>"],
186+
["Morphed", "<h2></h2>", "<h2></h2>"],
187+
["Morphed", "<div></div>", "<div></div>"],
188+
],
189+
);
190+
});
170191
});

0 commit comments

Comments
 (0)