perf: micro optimizations for vnode creation

This commit is contained in:
Evan You 2019-10-21 11:30:45 -04:00
parent 40ccbdeaac
commit 8be578b6b6

View File

@ -88,6 +88,7 @@ export interface VNode<HostNode = any, HostElement = any> {
// structure would be stable. This allows us to skip most children diffing
// and only worry about the dynamic nodes (indicated by patch flags).
const blockStack: (VNode[] | null)[] = []
let currentBlock: VNode[] | null = null
// Open a block.
// This must be called before `createBlock`. It cannot be part of `createBlock`
@ -101,7 +102,7 @@ const blockStack: (VNode[] | null)[] = []
// disableTracking is true when creating a fragment block, since a fragment
// always diffs its children.
export function openBlock(disableTracking?: boolean) {
blockStack.push(disableTracking ? null : [])
blockStack.push((currentBlock = disableTracking ? null : []))
}
let shouldTrack = true
@ -116,15 +117,20 @@ export function createBlock(
patchFlag?: number,
dynamicProps?: string[]
): VNode {
// avoid a block with optFlag tracking itself
// avoid a block with patchFlag tracking itself
shouldTrack = false
const vnode = createVNode(type, props, children, patchFlag, dynamicProps)
shouldTrack = true
const trackedNodes = blockStack.pop()
vnode.dynamicChildren =
trackedNodes && trackedNodes.length ? trackedNodes : EMPTY_ARR
// a block is always going to be patched
trackDynamicNode(vnode)
// save current block children on the block vnode
vnode.dynamicChildren = currentBlock || EMPTY_ARR
// close block
blockStack.pop()
currentBlock = blockStack[blockStack.length - 1] || null
// a block is always going to be patched, so track it as a child of its
// parent block
if (currentBlock !== null) {
currentBlock.push(vnode)
}
return vnode
}
@ -145,10 +151,10 @@ export function createVNode(
if (isReactive(props) || SetupProxySymbol in props) {
props = extend({}, props)
}
if (props.class != null) {
props.class = normalizeClass(props.class)
let { class: klass, style } = props
if (klass != null && !isString(klass)) {
props.class = normalizeClass(klass)
}
let { style } = props
if (style != null) {
// reactive state objects need to be cloned since they are likely to be
// mutated
@ -172,8 +178,8 @@ export function createVNode(
_isVNode: true,
type,
props,
key: (props && props.key) || null,
ref: (props && props.ref) || null,
key: (props !== null && props.key) || null,
ref: (props !== null && props.ref) || null,
children: null,
component: null,
suspense: null,
@ -195,23 +201,17 @@ export function createVNode(
// the next vnode so that it can be properly unmounted later.
if (
shouldTrack &&
(patchFlag ||
currentBlock !== null &&
(patchFlag > 0 ||
shapeFlag & ShapeFlags.STATEFUL_COMPONENT ||
shapeFlag & ShapeFlags.FUNCTIONAL_COMPONENT)
) {
trackDynamicNode(vnode)
currentBlock.push(vnode)
}
return vnode
}
function trackDynamicNode(vnode: VNode) {
const currentBlockDynamicNodes = blockStack[blockStack.length - 1]
if (currentBlockDynamicNodes != null) {
currentBlockDynamicNodes.push(vnode)
}
}
export function cloneVNode(vnode: VNode): VNode {
return {
_isVNode: true,