From: Evan You Date: Mon, 21 Oct 2019 15:30:45 +0000 (-0400) Subject: perf: micro optimizations for vnode creation X-Git-Tag: v3.0.0-alpha.0~357 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8be578b6b6886bd0f13bf197fa9778b6cc7dad1e;p=thirdparty%2Fvuejs%2Fcore.git perf: micro optimizations for vnode creation --- diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 5c5455ff82..632b160def 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -88,6 +88,7 @@ export interface VNode { // 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,