if (__COMPAT__) {
mountComponentInstance(vnode, container, isSVG, endNode)
} else {
- queueJob(() => {
- const instance = mountComponentInstance(
- vnode,
- container,
- isSVG,
- endNode
- )
- // cleanup if mount is invalidated before committed
- return () => {
- teardownComponentInstance(instance)
- }
- })
+ queueJob(() => mountComponentInstance(vnode, container, isSVG, endNode))
}
}
}
isSVG: boolean
) {
const refNode = platformNextSibling(getVNodeLastEl(prevVNode))
- removeVNode(prevVNode, container)
+ queueRemoveVNode(prevVNode, container)
mount(nextVNode, container, contextVNode, isSVG, refNode)
}
)
break
case ChildrenFlags.NO_CHILDREN:
- removeVNode(prevChildren as MountedVNode, container)
+ queueRemoveVNode(prevChildren as MountedVNode, container)
break
default:
- removeVNode(prevChildren as MountedVNode, container)
+ queueRemoveVNode(prevChildren as MountedVNode, container)
mountArrayChildren(
nextChildren as VNode[],
container,
default:
// MULTIPLE_CHILDREN
if (nextChildFlags === ChildrenFlags.SINGLE_VNODE) {
- removeChildren(prevChildren as MountedVNode[], container, endNode)
+ queueRemoveChildren(
+ prevChildren as MountedVNode[],
+ container,
+ endNode
+ )
mount(nextChildren as VNode, container, contextVNode, isSVG, endNode)
} else if (nextChildFlags === ChildrenFlags.NO_CHILDREN) {
- removeChildren(prevChildren as MountedVNode[], container, endNode)
+ queueRemoveChildren(
+ prevChildren as MountedVNode[],
+ container,
+ endNode
+ )
} else {
const prevLength = (prevChildren as VNode[]).length
const nextLength = (nextChildren as VNode[]).length
)
}
} else if (nextLength === 0) {
- removeChildren(prevChildren as MountedVNode[], container, endNode)
+ queueRemoveChildren(
+ prevChildren as MountedVNode[],
+ container,
+ endNode
+ )
} else if (
prevChildFlags === ChildrenFlags.KEYED_VNODES &&
nextChildFlags === ChildrenFlags.KEYED_VNODES
}
} else if (prevLength > nextLength) {
for (i = commonLength; i < prevLength; i++) {
- removeVNode(prevChildren[i], container)
+ queueRemoveVNode(prevChildren[i], container)
}
}
}
}
} else if (j > nextEnd) {
while (j <= prevEnd) {
- removeVNode(prevChildren[j++], container)
+ queueRemoveVNode(prevChildren[j++], container)
}
} else {
let prevStart = j
if (canRemoveWholeContent) {
canRemoveWholeContent = false
while (i > prevStart) {
- removeVNode(prevChildren[prevStart++], container)
+ queueRemoveVNode(prevChildren[prevStart++], container)
}
}
if (pos > j) {
}
}
if (!canRemoveWholeContent && j > nextEnd) {
- removeVNode(prevVNode, container)
+ queueRemoveVNode(prevVNode, container)
}
} else if (!canRemoveWholeContent) {
- removeVNode(prevVNode, container)
+ queueRemoveVNode(prevVNode, container)
}
}
} else {
if (canRemoveWholeContent) {
canRemoveWholeContent = false
while (i > prevStart) {
- removeVNode(prevChildren[prevStart++], container)
+ queueRemoveVNode(prevChildren[prevStart++], container)
}
}
nextVNode = nextChildren[j]
patch(prevVNode, nextVNode, container, contextVNode, isSVG)
patched++
} else if (!canRemoveWholeContent) {
- removeVNode(prevVNode, container)
+ queueRemoveVNode(prevVNode, container)
}
} else if (!canRemoveWholeContent) {
- removeVNode(prevVNode, container)
+ queueRemoveVNode(prevVNode, container)
}
}
}
// fast-path: if nothing patched remove all old and add all new
if (canRemoveWholeContent) {
- removeChildren(prevChildren as MountedVNode[], container, endNode)
+ queueRemoveChildren(prevChildren as MountedVNode[], container, endNode)
mountArrayChildren(
nextChildren,
container,
}
} else if (flags & VNodeFlags.PORTAL) {
if (childFlags & ChildrenFlags.MULTIPLE_VNODES) {
- removeChildren(
+ queueRemoveChildren(
children as MountedVNode[],
vnode.tag as RenderNode,
null
)
} else if (childFlags === ChildrenFlags.SINGLE_VNODE) {
- removeVNode(children as MountedVNode, vnode.tag as RenderNode)
+ queueRemoveVNode(children as MountedVNode, vnode.tag as RenderNode)
}
}
if (ref) {
}
}
+ function queueRemoveVNode(vnode: MountedVNode, container: RenderNode) {
+ queueNodeOp([removeVNode, vnode, container])
+ }
+
function removeVNode(vnode: MountedVNode, container: RenderNode) {
unmount(vnode)
const { el, flags, children, childFlags } = vnode
removeVNode(children as MountedVNode, container)
break
case ChildrenFlags.NO_CHILDREN:
- queueNodeOp([platformRemoveChild, container, el])
+ platformRemoveChild(container, el)
break
default:
for (let i = 0; i < (children as MountedVNode[]).length; i++) {
}
}
} else {
- queueNodeOp([platformRemoveChild, container, el])
+ platformRemoveChild(container, el)
}
}
;(vnode as any).el = null
}
+ function queueRemoveChildren(
+ children: MountedVNode[],
+ container: RenderNode,
+ refNode: RenderNode | null
+ ) {
+ queueNodeOp([removeChildren, children, container, refNode])
+ }
+
function removeChildren(
children: MountedVNode[],
container: RenderNode,
) {
unmountArrayChildren(children)
if (refNode === null) {
- queueNodeOp([platformClearContent, container])
+ platformClearContent(container)
} else {
for (let i = 0; i < children.length; i++) {
removeVNode(children[i], container)
container: RenderNode | null,
isSVG: boolean,
endNode: RenderNode | null
- ): ComponentInstance {
+ ): Function {
if (__DEV__) {
pushWarningContext(vnode)
}
)
}
- // this will be executed synchronously right here
instance.$vnode = renderInstanceRoot(instance) as MountedVNode
queuePostCommitCb(() => {
if (mounted) {
callLifecycleHookWithHandler(mounted, $proxy, ErrorTypes.MOUNTED)
}
+ instance._mounted = true
})
mount(instance.$vnode, container, vnode as MountedVNode, isSVG, endNode)
-
- instance._mounted = true
}
}, autorunOptions)
popWarningContext()
}
- return instance
+ // cleanup if mount is invalidated before committed
+ return () => {
+ teardownComponentInstance(instance)
+ }
}
function updateComponentInstance(
)
}
- const nextVNode = (instance.$vnode = renderInstanceRoot(
- instance
- ) as MountedVNode)
+ const nextVNode = renderInstanceRoot(instance) as MountedVNode
queuePostCommitCb(() => {
+ instance.$vnode = nextVNode
const el = nextVNode.el as RenderNode
if (__COMPAT__) {
// expose __vue__ for devtools
patch(prevVNode, vnode, container, null, false)
container.vnode = vnode
} else {
- removeVNode(prevVNode, container)
+ queueRemoveVNode(prevVNode, container)
container.vnode = null
}
}
}
const enum JobStatus {
- PENDING_PATCH = 1,
- PENDING_COMMIT,
- COMMITED
+ IDLE = 0,
+ PENDING_PATCH,
+ PENDING_COMMIT
}
interface Job extends Function {
status: JobStatus
ops: Op[]
post: Function[]
+ children: Job[]
cleanup: Function | null
expiration: number
}
export function queueJob(rawJob: Function) {
const job = rawJob as Job
+ if (currentJob) {
+ currentJob.children.push(job)
+ }
// 1. let's see if this invalidates any work that
// has already been done.
if (job.status === JobStatus.PENDING_COMMIT) {
// pending commit job invalidated
invalidateJob(job)
+ requeueInvalidatedJob(job)
} else if (job.status !== JobStatus.PENDING_PATCH) {
// a new job
insertNewJob(job)
}
}
+function requeueInvalidatedJob(job: Job) {
+ // With varying priorities we should insert job at correct position
+ // based on expiration time.
+ for (let i = 0; i < patchQueue.length; i++) {
+ if (job.expiration < patchQueue[i].expiration) {
+ patchQueue.splice(i, 0, job)
+ job.status = JobStatus.PENDING_PATCH
+ return
+ }
+ }
+ patchQueue.push(job)
+ job.status = JobStatus.PENDING_PATCH
+}
+
export function queuePostCommitCb(fn: Function) {
if (currentJob) {
currentJob.post.push(fn)
}
}
+function resetJob(job: Job) {
+ job.ops.length = 0
+ job.post.length = 0
+ job.children.length = 0
+}
+
function insertNewJob(job: Job) {
job.ops = job.ops || []
job.post = job.post || []
- job.expiration = getNow() + Priorities.NORMAL
+ job.children = job.children || []
+ resetJob(job)
+ // inherit parent job's expiration deadline
+ job.expiration = currentJob
+ ? currentJob.expiration
+ : getNow() + Priorities.NORMAL
patchQueue.push(job)
job.status = JobStatus.PENDING_PATCH
}
function invalidateJob(job: Job) {
- job.ops.length = 0
- job.post.length = 0
+ // recursively invalidate all child jobs
+ const { children } = job
+ for (let i = 0; i < children.length; i++) {
+ const child = children[i]
+ if (child.status === JobStatus.PENDING_COMMIT) {
+ invalidateJob(child)
+ } else if (child.status === JobStatus.PENDING_PATCH) {
+ patchQueue.splice(patchQueue.indexOf(child), 1)
+ child.status = JobStatus.IDLE
+ }
+ }
if (job.cleanup) {
job.cleanup()
job.cleanup = null
}
+ resetJob(job)
// remove from commit queue
- // and move it back to the patch queue
commitQueue.splice(commitQueue.indexOf(job), 1)
- // With varying priorities we should insert job at correct position
- // based on expiration time.
- for (let i = 0; i < patchQueue.length; i++) {
- if (job.expiration < patchQueue[i].expiration) {
- patchQueue.splice(i, 0, job)
- break
- }
- }
- job.status = JobStatus.PENDING_PATCH
+ job.status = JobStatus.IDLE
}
function patchJob(job: Job) {
for (let i = 0; i < ops.length; i++) {
applyOp(ops[i])
}
- ops.length = 0
// queue post commit cbs
if (post) {
postCommitQueue.push(...post)
- post.length = 0
}
- job.status = JobStatus.COMMITED
+ resetJob(job)
+ job.status = JobStatus.IDLE
}
function applyOp(op: Op) {