Skip to content

Commit 4f161fb

Browse files
committed
Fix issue potentially causing extra reorders
Not sorting children before executing the `insertBefore` calls in `init_hydrate` potentially caused extra `insertBefore` calls in `append`
1 parent c7b0bf6 commit 4f161fb

File tree

1 file changed

+21
-14
lines changed

1 file changed

+21
-14
lines changed

src/runtime/internal/dom.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ function init_hydrate(target: NodeEx) {
3636
if (target.hydrate_init) return;
3737
target.hydrate_init = true;
3838

39+
type NodeEx2 = NodeEx & {claim_order: number};
40+
3941
// We know that all children have claim_order values since the unclaimed have been detached
40-
const children = target.childNodes as NodeListOf<NodeEx & {claim_order: number}>;
42+
const children = target.childNodes as NodeListOf<NodeEx2>;
4143

4244
/*
4345
* Reorder claimed children optimally.
@@ -57,7 +59,7 @@ function init_hydrate(target: NodeEx) {
5759
*/
5860

5961
// Compute longest increasing subsequence
60-
// m: subsequence length j => index k of smallest value that ends an incresing subsequence of length j
62+
// m: subsequence length j => index k of smallest value that ends an increasing subsequence of length j
6163
const m = new Int32Array(children.length + 1);
6264
// Predecessor indices + 1
6365
const p = new Int32Array(children.length);
@@ -82,28 +84,34 @@ function init_hydrate(target: NodeEx) {
8284
}
8385

8486
// The longest increasing subsequence of nodes (initially reversed)
85-
const lis = [];
87+
const lis: NodeEx2[] = [];
8688
for (let cur = m[longest] + 1; cur != 0; cur = p[cur - 1]) {
8789
const node = children[cur - 1];
8890
lis.push(node);
8991
node.is_in_lis = true;
9092
}
91-
lis.reverse();
93+
lis.reverse();
9294

9395
// Move all nodes that aren't in the longest increasing subsequence
94-
const toMove: NodeEx[] = [];
96+
const toMove = lis.map(() => [] as NodeEx2[]);
97+
// For the nodes at the end
98+
toMove.push([]);
9599
for (let i = 0; i < children.length; i++) {
96-
if (!children[i].is_in_lis) {
97-
toMove.push(children[i]);
100+
const node = children[i];
101+
if (!node.is_in_lis) {
102+
const idx = upper_bound(0, lis.length, idx => lis[idx].claim_order, node.claim_order);
103+
toMove[idx].push(node);
98104
}
99105
}
100106

101-
toMove.forEach((node) => {
102-
const idx = upper_bound(0, lis.length, idx => lis[idx].claim_order, node.claim_order);
103-
if ((idx == 0) || (lis[idx - 1].claim_order != node.claim_order)) {
104-
const nxt = idx == lis.length ? null : lis[idx];
105-
target.insertBefore(node, nxt);
106-
}
107+
toMove.forEach((lst, idx) => {
108+
// We sort the nodes being moved to guarantee that their insertion order matches the claim order
109+
lst.sort((a, b) => a.claim_order - b.claim_order);
110+
111+
const anchor = idx < lis.length ? lis[idx] : null;
112+
lst.forEach(n => {
113+
target.insertBefore(n, anchor);
114+
});
107115
});
108116
}
109117

@@ -330,7 +338,6 @@ function claim_node<R extends ChildNodeEx>(nodes: ChildNodeArray, predicate: (no
330338
// Since we spliced before the last_index, we decrease it
331339
nodes.claim_info.last_index--;
332340
}
333-
detach(node);
334341
return node;
335342
}
336343
}

0 commit comments

Comments
 (0)