mirror of https://github.com/vuejs/core.git
perf: cache static children on parent
This commit is contained in:
parent
41509dcc61
commit
479ea96e59
|
@ -20,8 +20,8 @@ describe('api: template', () => {
|
||||||
|
|
||||||
test('nthChild', () => {
|
test('nthChild', () => {
|
||||||
const t = template('<div><span><b>nested</b></span><p></p></div>')
|
const t = template('<div><span><b>nested</b></span><p></p></div>')
|
||||||
const root = t()
|
const root = t() as ParentNode
|
||||||
const span = nthChild(root, 0)
|
const span = nthChild(root, 0) as ParentNode
|
||||||
const b = nthChild(span, 0)
|
const b = nthChild(span, 0)
|
||||||
const p = nthChild(root, 1)
|
const p = nthChild(root, 1)
|
||||||
expect(span).toBe(root.firstChild)
|
expect(span).toBe(root.firstChild)
|
||||||
|
@ -31,7 +31,7 @@ describe('api: template', () => {
|
||||||
|
|
||||||
test('next', () => {
|
test('next', () => {
|
||||||
const t = template('<div><span></span><b></b><p></p></div>')
|
const t = template('<div><span></span><b></b><p></p></div>')
|
||||||
const root = t()
|
const root = t() as ParentNode
|
||||||
const span = child(root as ParentNode)
|
const span = child(root as ParentNode)
|
||||||
const b = next(span)
|
const b = next(span)
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ function performHydration<T>(
|
||||||
// optimize anchor cache lookup
|
// optimize anchor cache lookup
|
||||||
;(Comment.prototype as any).$fe = undefined
|
;(Comment.prototype as any).$fe = undefined
|
||||||
;(Node.prototype as any).$idx = undefined
|
;(Node.prototype as any).$idx = undefined
|
||||||
|
;(Node.prototype as any).$children = undefined
|
||||||
isOptimized = true
|
isOptimized = true
|
||||||
}
|
}
|
||||||
enableHydrationNodeLookup()
|
enableHydrationNodeLookup()
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type ChildItem,
|
type ChildItem,
|
||||||
|
type InsertionParent,
|
||||||
getHydrationState,
|
getHydrationState,
|
||||||
getTemplateChildren,
|
|
||||||
} from '../insertionState'
|
} from '../insertionState'
|
||||||
|
|
||||||
export function createElement(tagName: string): HTMLElement {
|
export function createElement(tagName: string): HTMLElement {
|
||||||
|
@ -46,23 +46,23 @@ const __txt: typeof __child = (node: ParentNode): Node => {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @__NO_SIDE_EFFECTS__ */
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export function _child(node: ParentNode): Node {
|
export function _child(node: InsertionParent): Node {
|
||||||
const templateChildren = getTemplateChildren(node)
|
const children = node.$children
|
||||||
return templateChildren ? templateChildren[0] : node.firstChild!
|
return children ? children[0] : node.firstChild!
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hydration-specific version of `child`.
|
* Hydration-specific version of `child`.
|
||||||
*/
|
*/
|
||||||
/* @__NO_SIDE_EFFECTS__ */
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export function __child(node: ParentNode & { $lpn?: Node }): Node {
|
export function __child(node: ParentNode): Node {
|
||||||
return __nthChild(node, 0)!
|
return __nthChild(node, 0)!
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @__NO_SIDE_EFFECTS__ */
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export function _nthChild(node: Node, i: number): Node {
|
export function _nthChild(node: InsertionParent, i: number): Node {
|
||||||
const templateChildren = getTemplateChildren(node as ParentNode)
|
const children = node.$children
|
||||||
return templateChildren ? templateChildren[i] : node.childNodes[i]
|
return children ? children[i] : node.childNodes[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,10 +92,8 @@ export function __nthChild(node: Node, i: number): Node {
|
||||||
|
|
||||||
/* @__NO_SIDE_EFFECTS__ */
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export function _next(node: Node): Node {
|
export function _next(node: Node): Node {
|
||||||
const templateChildren = getTemplateChildren(node.parentNode!)
|
const children = (node.parentNode! as InsertionParent).$children
|
||||||
return templateChildren
|
return children ? children[(node as ChildItem).$idx + 1] : node.nextSibling!
|
||||||
? templateChildren[(node as ChildItem).$idx + 1]
|
|
||||||
: node.nextSibling!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import { isHydrating } from './dom/hydration'
|
import { isHydrating } from './dom/hydration'
|
||||||
export interface ChildItem extends ChildNode {
|
export type ChildItem = ChildNode & { $idx: number }
|
||||||
$idx: number
|
export type InsertionParent = ParentNode & { $children?: ChildItem[] }
|
||||||
}
|
|
||||||
type HydrationState = {
|
type HydrationState = {
|
||||||
logicalChildren: ChildItem[]
|
logicalChildren: ChildItem[]
|
||||||
prevDynamicCount: number
|
prevDynamicCount: number
|
||||||
insertionAnchors: Map<Node, number> | null
|
insertionAnchors: Map<Node, number> | null
|
||||||
appendAnchor: Node | null
|
appendAnchor: Node | null
|
||||||
}
|
}
|
||||||
export let insertionParent: ParentNode | undefined
|
export let insertionParent: InsertionParent | undefined
|
||||||
export let insertionAnchor: Node | 0 | undefined | null
|
export let insertionAnchor: Node | 0 | undefined | null
|
||||||
|
|
||||||
const templateChildrenCache = new WeakMap<ParentNode, ChildItem[]>()
|
|
||||||
|
|
||||||
const hydrationStateCache = new WeakMap<ParentNode, HydrationState>()
|
const hydrationStateCache = new WeakMap<ParentNode, HydrationState>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,22 +85,22 @@ function initializeHydrationState(
|
||||||
|
|
||||||
function cacheTemplateChildren(
|
function cacheTemplateChildren(
|
||||||
anchor: number | Node | null | undefined,
|
anchor: number | Node | null | undefined,
|
||||||
parent: ParentNode,
|
parent: InsertionParent,
|
||||||
) {
|
) {
|
||||||
// special handling append anchor value to null
|
// special handling append anchor value to null
|
||||||
insertionAnchor =
|
insertionAnchor =
|
||||||
typeof anchor === 'number' && anchor > 0 ? null : (anchor as Node)
|
typeof anchor === 'number' && anchor > 0 ? null : (anchor as Node)
|
||||||
|
|
||||||
if (!templateChildrenCache.has(parent)) {
|
if (!parent.$children) {
|
||||||
const nodes = parent.childNodes
|
const nodes = parent.childNodes
|
||||||
const len = nodes.length
|
const len = nodes.length
|
||||||
const children = new Array(len)
|
const children = new Array(len) as ChildItem[]
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
const node = nodes[i] as ChildItem
|
const node = nodes[i] as ChildItem
|
||||||
node.$idx = i
|
node.$idx = i
|
||||||
children[i] = node
|
children[i] = node
|
||||||
}
|
}
|
||||||
templateChildrenCache.set(parent, children)
|
parent.$children = children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,12 +108,6 @@ export function resetInsertionState(): void {
|
||||||
insertionParent = insertionAnchor = undefined
|
insertionParent = insertionAnchor = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTemplateChildren(
|
|
||||||
parent: ParentNode,
|
|
||||||
): ChildItem[] | undefined {
|
|
||||||
return templateChildrenCache.get(parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getHydrationState(
|
export function getHydrationState(
|
||||||
parent: ParentNode,
|
parent: ParentNode,
|
||||||
): HydrationState | undefined {
|
): HydrationState | undefined {
|
||||||
|
|
Loading…
Reference in New Issue