From 93a6a470b96ae309801133d30ff9c9c2b790ab14 Mon Sep 17 00:00:00 2001 From: Benedikt Meurer Date: Wed, 26 Jun 2019 19:24:05 +0200 Subject: [PATCH 1/3] Slightly improve performance of hydration. Avoid loading nodeType and data couple times from the same node in a row, but instead load them only once, which will help engines to run this code faster, especially during startup of the application. The general approach is still not ideal, since hydrating this way forces the browser engine to materialize JavaScript wrapper objects for all DOM nodes, even if they are not interesting to hydration itself. --- .../src/client/ReactDOMHostConfig.js | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index ad51fdaae44b..a1a3a3737671 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -670,21 +670,31 @@ export function registerSuspenseInstanceRetry( instance._reactRetry = callback; } +function isHydratableNode(node: Node) { + const nodeType = node.nodeType; + if (nodeType === ELEMENT_NODE || nodeType === TEXT_NODE) { + return true; + } + if (enableSuspenseServerRenderer) { + if (nodeType === COMMENT_NODE) { + return false; + } + const nodeData = (node: any).data; + return ( + nodeData === SUSPENSE_START_DATA || + nodeData === SUSPENSE_FALLBACK_START_DATA || + nodeData === SUSPENSE_PENDING_START_DATA + ); + } + return false; +} + export function getNextHydratableSibling( instance: HydratableInstance, ): null | HydratableInstance { let node = instance.nextSibling; // Skip non-hydratable nodes. - while ( - node && - node.nodeType !== ELEMENT_NODE && - node.nodeType !== TEXT_NODE && - (!enableSuspenseServerRenderer || - node.nodeType !== COMMENT_NODE || - ((node: any).data !== SUSPENSE_START_DATA && - (node: any).data !== SUSPENSE_PENDING_START_DATA && - (node: any).data !== SUSPENSE_FALLBACK_START_DATA)) - ) { + while (node != null && !isHydratableNode(node)) { node = node.nextSibling; } return (node: any); @@ -693,21 +703,12 @@ export function getNextHydratableSibling( export function getFirstHydratableChild( parentInstance: Container | Instance, ): null | HydratableInstance { - let next = parentInstance.firstChild; + let node = parentInstance.firstChild; // Skip non-hydratable nodes. - while ( - next && - next.nodeType !== ELEMENT_NODE && - next.nodeType !== TEXT_NODE && - (!enableSuspenseServerRenderer || - next.nodeType !== COMMENT_NODE || - ((next: any).data !== SUSPENSE_START_DATA && - (next: any).data !== SUSPENSE_FALLBACK_START_DATA && - (next: any).data !== SUSPENSE_PENDING_START_DATA)) - ) { - next = next.nextSibling; + while (node != null && !isHydratableNode(node)) { + node = node.nextSibling; } - return (next: any); + return (node: any); } export function hydrateInstance( From 5b24cfd810b27ec07171cdaed90d895cbab7473d Mon Sep 17 00:00:00 2001 From: Benedikt Meurer Date: Wed, 26 Jun 2019 22:59:26 +0200 Subject: [PATCH 2/3] Fix condition for COMMENT_NODEs. --- packages/react-dom/src/client/ReactDOMHostConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index a1a3a3737671..2060c06ef6dd 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -677,7 +677,7 @@ function isHydratableNode(node: Node) { } if (enableSuspenseServerRenderer) { if (nodeType === COMMENT_NODE) { - return false; + return true; } const nodeData = (node: any).data; return ( From fba82affe0cc3050d25fe6ecbcd03be4c4246a27 Mon Sep 17 00:00:00 2001 From: Benedikt Meurer Date: Wed, 26 Jun 2019 23:06:50 +0200 Subject: [PATCH 3/3] Improve general code readability --- .../src/client/ReactDOMHostConfig.js | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index 2060c06ef6dd..81c5f2fd9235 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -670,45 +670,40 @@ export function registerSuspenseInstanceRetry( instance._reactRetry = callback; } -function isHydratableNode(node: Node) { - const nodeType = node.nodeType; - if (nodeType === ELEMENT_NODE || nodeType === TEXT_NODE) { - return true; - } - if (enableSuspenseServerRenderer) { - if (nodeType === COMMENT_NODE) { - return true; +function getNextHydratable(node) { + // Skip non-hydratable nodes. + for (; node != null; node = node.nextSibling) { + const nodeType = node.nodeType; + if (nodeType === ELEMENT_NODE || nodeType === TEXT_NODE) { + break; + } + if (enableSuspenseServerRenderer) { + if (nodeType === COMMENT_NODE) { + break; + } + const nodeData = (node: any).data; + if ( + nodeData === SUSPENSE_START_DATA || + nodeData === SUSPENSE_FALLBACK_START_DATA || + nodeData === SUSPENSE_PENDING_START_DATA + ) { + break; + } } - const nodeData = (node: any).data; - return ( - nodeData === SUSPENSE_START_DATA || - nodeData === SUSPENSE_FALLBACK_START_DATA || - nodeData === SUSPENSE_PENDING_START_DATA - ); } - return false; + return (node: any); } export function getNextHydratableSibling( instance: HydratableInstance, ): null | HydratableInstance { - let node = instance.nextSibling; - // Skip non-hydratable nodes. - while (node != null && !isHydratableNode(node)) { - node = node.nextSibling; - } - return (node: any); + return getNextHydratable(instance.nextSibling); } export function getFirstHydratableChild( parentInstance: Container | Instance, ): null | HydratableInstance { - let node = parentInstance.firstChild; - // Skip non-hydratable nodes. - while (node != null && !isHydratableNode(node)) { - node = node.nextSibling; - } - return (node: any); + return getNextHydratable(parentInstance.firstChild); } export function hydrateInstance(