Skip to content

Commit 7d182ba

Browse files
perf: go back to calculating outerHTML morphed nodes manually. This is 2n fewer array allocations, where n is the number of DOM nodes with children.
1 parent f522f06 commit 7d182ba

File tree

1 file changed

+26
-15
lines changed

1 file changed

+26
-15
lines changed

src/idiomorph.js

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -155,30 +155,44 @@ var Idiomorph = (function () {
155155
const newNode = normalizeParent(newContent);
156156
const ctx = createMorphContext(oldNode, newNode, config);
157157

158-
return saveAndRestoreFocus(ctx, () => {
158+
const morphedNodes = saveAndRestoreFocus(ctx, () => {
159159
return withHeadBlocking(
160160
ctx,
161161
oldNode,
162162
newNode,
163163
/** @param {MorphContext} ctx */ (ctx) => {
164-
let morphedNodes;
165164
if (ctx.morphStyle === "innerHTML") {
166-
morphedNodes = morphChildren(ctx, oldNode, newNode);
165+
morphChildren(ctx, oldNode, newNode);
166+
return Array.from(oldNode.childNodes);
167167
} else {
168168
// outerHTML
169-
morphedNodes = morphChildren(
169+
const oldParent = normalizeParent(oldNode);
170+
171+
// basis for calulating which nodes were morphed
172+
// since there maybe unmorphed sibling nodes
173+
let childNodes = Array.from(oldParent.childNodes);
174+
const index = childNodes.indexOf(oldNode);
175+
// how many elements are to the right of the oldNode
176+
const rightMargin = childNodes.length - (index + 1);
177+
178+
morphChildren(
170179
ctx,
171-
normalizeParent(oldNode),
180+
oldParent,
172181
newNode,
173182
oldNode,
174183
oldNode.nextSibling,
175184
);
185+
186+
// rebuild childNodes
187+
childNodes = Array.from(oldParent.childNodes);
188+
return childNodes.slice(index, childNodes.length - rightMargin);
176189
}
177-
ctx.pantry.remove();
178-
return morphedNodes;
179190
},
180191
);
181192
});
193+
194+
ctx.pantry.remove();
195+
return morphedNodes;
182196
}
183197

184198
/**
@@ -241,7 +255,6 @@ var Idiomorph = (function () {
241255
* @param {Element} newParent the parent element of the new content
242256
* @param {Node|null} [insertionPoint] the point in the DOM we start morphing at (defaults to first child)
243257
* @param {Node|null} [endPoint] the point in the DOM we stop morphing at (defaults to after last child)
244-
* @returns {Node[]}
245258
*/
246259
function morphChildren(
247260
ctx,
@@ -263,7 +276,7 @@ var Idiomorph = (function () {
263276
insertionPoint ||= oldParent.firstChild;
264277

265278
// run through all the new content
266-
const morphedNodes = [...newParent.childNodes].map((newChild) => {
279+
for (const newChild of newParent.childNodes) {
267280
// once we reach the end of the old parent content skip to the end and insert the rest
268281
if (insertionPoint && insertionPoint != endPoint) {
269282
const bestMatch = findBestMatch(
@@ -279,7 +292,7 @@ var Idiomorph = (function () {
279292
}
280293
morphNode(bestMatch, newChild, ctx);
281294
insertionPoint = bestMatch.nextSibling;
282-
return bestMatch;
295+
continue;
283296
}
284297
}
285298

@@ -293,21 +306,19 @@ var Idiomorph = (function () {
293306
ctx,
294307
);
295308
morphNode(movedChild, newChild, ctx);
296-
return movedChild;
309+
continue;
297310
}
298311

299312
// last resort: insert the new node from scratch
300-
return createNode(oldParent, newChild, insertionPoint, ctx);
301-
});
313+
createNode(oldParent, newChild, insertionPoint, ctx);
314+
}
302315

303316
// remove any remaining old nodes that didn't match up with new content
304317
while (insertionPoint && insertionPoint != endPoint) {
305318
const tempNode = insertionPoint;
306319
insertionPoint = insertionPoint.nextSibling;
307320
removeNode(tempNode, ctx);
308321
}
309-
310-
return morphedNodes.filter((e) => e != null);
311322
}
312323

313324
/**

0 commit comments

Comments
 (0)