From 48cde497e88fffcc72d9106f4cadc0fe773090e1 Mon Sep 17 00:00:00 2001 From: Taku Amano Date: Mon, 29 Jul 2024 12:28:55 +0900 Subject: [PATCH 1/2] fix(jsx/dom): fix performance issue with adding many new node listings * First time rendering does not need to look for elements from child nodes ** Avoid unnecessary checks with `node.pP`. * Sibling elements are always searched, so there is no need for a for loop. ** Need only `findInsertBefore(node.vC[0])` --- src/jsx/dom/render.ts | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/jsx/dom/render.ts b/src/jsx/dom/render.ts index dbb8478ba..1d9b935e6 100644 --- a/src/jsx/dom/render.ts +++ b/src/jsx/dom/render.ts @@ -271,24 +271,11 @@ const getNextChildren = ( } const findInsertBefore = (node: Node | undefined): SupportedElement | Text | null => { - if (!node) { - return null - } else if (node.tag === HONO_PORTAL_ELEMENT) { - return findInsertBefore(node.nN) - } else if (node.e) { - return node.e - } - - if (node.vC) { - for (let i = 0, len = node.vC.length; i < len; i++) { - const e = findInsertBefore(node.vC[i]) - if (e) { - return e - } - } - } - - return findInsertBefore(node.nN) + return !node + ? null + : node.tag === HONO_PORTAL_ELEMENT + ? findInsertBefore(node.nN) + : node.e || (node.vC && node.pP && findInsertBefore(node.vC[0])) || findInsertBefore(node.nN) } const removeNode = (node: Node): void => { From 0784652220c4b0f67cca2c22dbba9eb390f33d0a Mon Sep 17 00:00:00 2001 From: Taku Amano Date: Mon, 29 Jul 2024 13:16:54 +0900 Subject: [PATCH 2/2] test(jsx/dom): add test for performance --- src/jsx/dom/index.test.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/jsx/dom/index.test.tsx b/src/jsx/dom/index.test.tsx index 5b54c357d..8f9d0c7d7 100644 --- a/src/jsx/dom/index.test.tsx +++ b/src/jsx/dom/index.test.tsx @@ -117,6 +117,24 @@ describe('DOM', () => { expect(root.innerHTML).toBe('Hello') }) + describe('performance', () => { + it('should be O(N) for each additional element', () => { + const App = () => ( + <> + {Array.from({ length: 1000 }, (_, i) => ( +
+ {i} +
+ ))} + + ) + render(, root) + expect(root.innerHTML).toBe( + Array.from({ length: 1000 }, (_, i) => `
${i}
`).join('') + ) + }) + }) + describe('attribute', () => { it('simple', () => { const App = () =>