chore: add some comments

This commit is contained in:
daiwei 2025-09-09 10:07:23 +08:00
parent 2ca2c5f4f1
commit 8978ef759f
3 changed files with 39 additions and 20 deletions

View File

@ -29,8 +29,9 @@ function performHydration<T>(
locateHydrationNode = locateHydrationNodeImpl
// optimize anchor cache lookup
;(Comment.prototype as any).$fe = undefined
;(Node.prototype as any).$pns = undefined
;(Node.prototype as any).$idx = undefined
;(Node.prototype as any).$auc = undefined
;(Node.prototype as any).$uc = undefined
;(Node.prototype as any).$children = undefined
isOptimized = true
}
@ -140,20 +141,28 @@ function locateHydrationNodeImpl(): void {
const { prevDynamicCount, logicalChildren, appendAnchor } = hydrationState
// prepend
if (insertionAnchor === 0) {
// use prevDynamicCount as index to locate the hydration node
node = logicalChildren[prevDynamicCount]
}
// insert
else if (insertionAnchor instanceof Node) {
const usedCount = (insertionAnchor as ChildItem).$auc
// handling insertion anchors:
// 1. first encounter: use insertionAnchor itself as the hydration node
// 2. subsequent: use node following the insertionAnchor as the hydration node
// used count tracks how many times insertionAnchor has been used, ensuring
// consecutive insert operations locate the correct hydration node.
let { $idx, $uc: usedCount } = insertionAnchor as ChildItem
if (usedCount !== undefined) {
node =
logicalChildren[(insertionAnchor as ChildItem).$idx + usedCount + 1]
;(insertionAnchor as ChildItem).$auc = usedCount + 1
node = logicalChildren[$idx + usedCount + 1]
usedCount++
} else {
node = insertionAnchor
hydrationState.insertionAnchorCount++
;(insertionAnchor as ChildItem).$auc = 0
// first use of this anchor: it doesn't consume the next child
// so we track unique anchor appearances for later offset correction
hydrationState.uniqueAnchorCount++
usedCount = 0
}
;(insertionAnchor as ChildItem).$uc = usedCount
}
// append
else {
@ -161,14 +170,18 @@ function locateHydrationNodeImpl(): void {
node = logicalChildren[(appendAnchor as ChildItem).$idx + 1]
} else {
node =
// insertionAnchor is null, indicates no previous static nodes
// use the first child as hydration node
insertionAnchor === null
? logicalChildren[0]
: // insertionAnchor is a number > 0
// indicates how many static nodes precede the node to append
// use it as index to locate the hydration node
logicalChildren[prevDynamicCount + insertionAnchor]
}
hydrationState.appendAnchor = node
}
hydrationState.prevDynamicCount++
} else {
node = currentHydrationNode

View File

@ -72,7 +72,7 @@ export function _nthChild(node: InsertionParent, i: number): Node {
export function __nthChild(node: Node, i: number): Node {
const hydrationState = getHydrationState(node as ParentNode)
if (hydrationState) {
const { prevDynamicCount, insertionAnchorCount, logicalChildren } =
const { prevDynamicCount, uniqueAnchorCount, logicalChildren } =
hydrationState
// prevDynamicCount tracks how many dynamic nodes have been processed
// so far (prepend/insert/append).
@ -80,11 +80,11 @@ export function __nthChild(node: Node, i: number): Node {
// anchor node itself and do NOT consume the next child in `logicalChildren`,
// yet prevDynamicCount is still incremented. This overcounts the base
// offset by 1 per unique anchor that has appeared.
// insertionAnchorCount equals the number of unique anchors seen, so we
// uniqueAnchorCount equals the number of unique anchors seen, so we
// subtract it to neutralize those "first-use doesn't consume" cases:
// base = prevDynamicCount - insertionAnchorCount
// base = prevDynamicCount - uniqueAnchorCount
// Then index from this base: logicalChildren[base + i].
return logicalChildren[prevDynamicCount - insertionAnchorCount + i]
return logicalChildren[prevDynamicCount - uniqueAnchorCount + i]
}
return node.childNodes[i]
}
@ -103,9 +103,8 @@ export function __next(node: Node): Node {
const hydrationState = getHydrationState(node.parentNode!)
if (hydrationState) {
const { logicalChildren } = hydrationState
return logicalChildren[
(node as ChildItem).$idx + ((node as ChildItem).$auc || 0) + 1
]
const { $idx, $uc: usedCount = 0 } = node as ChildItem
return logicalChildren[$idx + usedCount + 1]
}
return node.nextSibling!
}

View File

@ -1,17 +1,24 @@
import { isHydrating } from './dom/hydration'
export type ChildItem = ChildNode & { $idx: number; $auc?: number }
export type ChildItem = ChildNode & {
$idx: number
// used count as an anchor
$uc?: number
}
export type InsertionParent = ParentNode & { $children?: ChildItem[] }
type HydrationState = {
// static nodes and the start anchors of fragments
logicalChildren: ChildItem[]
// hydrated dynamic children count so far
prevDynamicCount: number
insertionAnchorCount: number
// number of unique insertion anchors that have appeared
uniqueAnchorCount: number
// current append anchor
appendAnchor: Node | null
}
export let insertionParent: InsertionParent | undefined
export let insertionAnchor: Node | 0 | undefined | null
const hydrationStateCache = new WeakMap<ParentNode, HydrationState>()
export let insertionParent: InsertionParent | undefined
export let insertionAnchor: Node | 0 | undefined | null
/**
* This function is called before a block type that requires insertion
@ -77,7 +84,7 @@ function initializeHydrationState(
hydrationStateCache.set(parent, {
logicalChildren,
prevDynamicCount: 0,
insertionAnchorCount: 0,
uniqueAnchorCount: 0,
appendAnchor: null,
})
}