From 36768965337db739e75d7fbfb9e098db91b638f4 Mon Sep 17 00:00:00 2001 From: Andreas Ehrencrona Date: Tue, 8 Jun 2021 18:29:35 +0400 Subject: [PATCH 1/3] Improved hydration performance by less reordering of nodes --- src/runtime/internal/dom.ts | 48 +++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 40471c298058..7eed56916192 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -1,11 +1,48 @@ import { has_prop } from './utils'; -export function append(target: Node, node: Node) { - target.appendChild(node); -} +interface ClaimedNode extends Node { + /** + * When a node is claimed, we know all its children will be appended during mount. + * Keep track of which children have already been re-appended, so we do not reorder them multiple times. + */ + appendAt?: number; +} + +export function append(target: ClaimedNode, node: Node) { + if (target.appendAt == null) { + target.appendChild(node); + } else { + const appendAt = target.appendAt; + const childNodes = target.childNodes; + const nextNode = childNodes[appendAt]; + + if (nextNode != node) { + if (nextNode) { + target.insertBefore(node, nextNode); + } else { + target.appendChild(node); + } + } + + target.appendAt = childNodes.length == appendAt + 1 ? undefined : appendAt + 1; + } +} + +export function insert(target: ClaimedNode, node: Node, anchor?: Node) { + if ((target as ClaimedNode).appendAt == null) { + target.insertBefore(node, anchor || null); + } else if (anchor == null) { + append(target, node); + } else { + const appendAt = target.appendAt; + const anchorIndex = Array.prototype.indexOf.call(target.childNodes, anchor); + + if (anchorIndex < appendAt) { + target.appendAt = target.childNodes.length == appendAt + 1 ? undefined : appendAt + 1; + } -export function insert(target: Node, node: Node, anchor?: Node) { - target.insertBefore(node, anchor || null); + target.insertBefore(node, anchor || null); + } } export function detach(node: Node) { @@ -168,6 +205,7 @@ export function claim_element(nodes, name, attributes, svg) { for (let k = 0; k < remove.length; k++) { node.removeAttribute(remove[k]); } + (node as ClaimedNode).appendAt = 0; return nodes.splice(i, 1)[0]; } } From be778960644f8a3b8f657311dac011379f929bec Mon Sep 17 00:00:00 2001 From: Andreas Ehrencrona Date: Wed, 9 Jun 2021 08:27:08 +0400 Subject: [PATCH 2/3] micro-optimization --- src/runtime/internal/dom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 7eed56916192..c6e2481d6dab 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -41,7 +41,7 @@ export function insert(target: ClaimedNode, node: Node, anchor?: Node) { target.appendAt = target.childNodes.length == appendAt + 1 ? undefined : appendAt + 1; } - target.insertBefore(node, anchor || null); + target.insertBefore(node, anchor); } } From b1b604ac11899b78c8f02a1ee344387ab94c0918 Mon Sep 17 00:00:00 2001 From: Andreas Ehrencrona Date: Wed, 9 Jun 2021 08:51:25 +0400 Subject: [PATCH 3/3] unnecessary case --- src/runtime/internal/dom.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index c6e2481d6dab..b607fe5c9142 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -17,11 +17,7 @@ export function append(target: ClaimedNode, node: Node) { const nextNode = childNodes[appendAt]; if (nextNode != node) { - if (nextNode) { - target.insertBefore(node, nextNode); - } else { - target.appendChild(node); - } + target.insertBefore(node, nextNode); } target.appendAt = childNodes.length == appendAt + 1 ? undefined : appendAt + 1;