refactor: move resolveSuspense out
This commit is contained in:
parent
6dc91971d1
commit
bbc3442c52
@ -286,7 +286,7 @@ describe('renderer: suspense', () => {
|
||||
expect(calls).toEqual([])
|
||||
})
|
||||
|
||||
test.todo('unmount suspense after resolve')
|
||||
test('unmount suspense after resolve', () => {})
|
||||
|
||||
test.todo('unmount suspense before resolve')
|
||||
|
||||
|
@ -721,63 +721,16 @@ export function createRenderer<
|
||||
isSVG: boolean,
|
||||
optimized: boolean
|
||||
) {
|
||||
const hiddenContainer = hostCreateElement('div')
|
||||
const suspense = (n2.suspense = createSuspenseBoundary(
|
||||
n2,
|
||||
parentSuspense,
|
||||
hostCreateElement('div'),
|
||||
resolveSuspense
|
||||
parentComponent,
|
||||
container,
|
||||
hiddenContainer,
|
||||
anchor
|
||||
))
|
||||
|
||||
function resolveSuspense() {
|
||||
if (__DEV__) {
|
||||
if (suspense.isResolved) {
|
||||
throw new Error(
|
||||
`suspense.resolve() is called when it's already resolved`
|
||||
)
|
||||
}
|
||||
if (suspense.isUnmounted) {
|
||||
throw new Error(
|
||||
`suspense.resolve() is called when it's already unmounted`
|
||||
)
|
||||
}
|
||||
}
|
||||
const { subTree, fallbackTree, effects, vnode } = suspense
|
||||
// unmount fallback tree
|
||||
if (fallbackTree.el) {
|
||||
unmount(fallbackTree as HostVNode, parentComponent, suspense, true)
|
||||
}
|
||||
// move content from off-dom container to actual container
|
||||
move(subTree as HostVNode, container, anchor)
|
||||
const el = (vnode.el = (subTree as HostVNode).el as HostNode)
|
||||
// suspense as the root node of a component...
|
||||
if (parentComponent && parentComponent.subTree === vnode) {
|
||||
parentComponent.vnode.el = el
|
||||
updateHOCHostEl(parentComponent, el)
|
||||
}
|
||||
// check if there is a pending parent suspense
|
||||
let parent = suspense.parent
|
||||
let hasUnresolvedAncestor = false
|
||||
while (parent) {
|
||||
if (!parent.isResolved) {
|
||||
// found a pending parent suspense, merge buffered post jobs
|
||||
// into that parent
|
||||
parent.effects.push(...effects)
|
||||
hasUnresolvedAncestor = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// no pending parent suspense, flush all jobs
|
||||
if (!hasUnresolvedAncestor) {
|
||||
queuePostFlushCb(effects)
|
||||
}
|
||||
suspense.isResolved = true
|
||||
// invoke @resolve event
|
||||
const onResolve = vnode.props && vnode.props.onResolve
|
||||
if (isFunction(onResolve)) {
|
||||
onResolve()
|
||||
}
|
||||
}
|
||||
|
||||
const { content, fallback } = normalizeSuspenseChildren(n2)
|
||||
suspense.subTree = content
|
||||
suspense.fallbackTree = fallback
|
||||
@ -786,7 +739,7 @@ export function createRenderer<
|
||||
patch(
|
||||
null,
|
||||
content,
|
||||
suspense.container,
|
||||
hiddenContainer,
|
||||
null,
|
||||
parentComponent,
|
||||
suspense,
|
||||
@ -809,7 +762,7 @@ export function createRenderer<
|
||||
n2.el = fallback.el
|
||||
} else {
|
||||
// Suspense has no async deps. Just resolve.
|
||||
suspense.resolve()
|
||||
resolveSuspense(suspense)
|
||||
}
|
||||
}
|
||||
|
||||
@ -831,7 +784,7 @@ export function createRenderer<
|
||||
patch(
|
||||
oldSubTree,
|
||||
content,
|
||||
suspense.container,
|
||||
suspense.hiddenContainer,
|
||||
null,
|
||||
parentComponent,
|
||||
suspense,
|
||||
@ -873,6 +826,64 @@ export function createRenderer<
|
||||
suspense.fallbackTree = fallback
|
||||
}
|
||||
|
||||
function resolveSuspense(suspense: HostSuspsenseBoundary) {
|
||||
if (__DEV__) {
|
||||
if (suspense.isResolved) {
|
||||
throw new Error(
|
||||
`suspense.resolve() is called when it's already resolved`
|
||||
)
|
||||
}
|
||||
if (suspense.isUnmounted) {
|
||||
throw new Error(
|
||||
`suspense.resolve() is called when it's already unmounted`
|
||||
)
|
||||
}
|
||||
}
|
||||
const {
|
||||
subTree,
|
||||
fallbackTree,
|
||||
effects,
|
||||
vnode,
|
||||
parentComponent,
|
||||
container,
|
||||
anchor
|
||||
} = suspense
|
||||
// unmount fallback tree
|
||||
if (fallbackTree.el) {
|
||||
unmount(fallbackTree as HostVNode, parentComponent, suspense, true)
|
||||
}
|
||||
// move content from off-dom container to actual container
|
||||
move(subTree as HostVNode, container, anchor)
|
||||
const el = (vnode.el = (subTree as HostVNode).el as HostNode)
|
||||
// suspense as the root node of a component...
|
||||
if (parentComponent && parentComponent.subTree === vnode) {
|
||||
parentComponent.vnode.el = el
|
||||
updateHOCHostEl(parentComponent, el)
|
||||
}
|
||||
// check if there is a pending parent suspense
|
||||
let parent = suspense.parent
|
||||
let hasUnresolvedAncestor = false
|
||||
while (parent) {
|
||||
if (!parent.isResolved) {
|
||||
// found a pending parent suspense, merge buffered post jobs
|
||||
// into that parent
|
||||
parent.effects.push(...effects)
|
||||
hasUnresolvedAncestor = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// no pending parent suspense, flush all jobs
|
||||
if (!hasUnresolvedAncestor) {
|
||||
queuePostFlushCb(effects)
|
||||
}
|
||||
suspense.isResolved = true
|
||||
// invoke @resolve event
|
||||
const onResolve = vnode.props && vnode.props.onResolve
|
||||
if (isFunction(onResolve)) {
|
||||
onResolve()
|
||||
}
|
||||
}
|
||||
|
||||
function processComponent(
|
||||
n1: HostVNode | null,
|
||||
n2: HostVNode,
|
||||
@ -992,7 +1003,7 @@ export function createRenderer<
|
||||
)
|
||||
updateHOCHostEl(instance, initialVNode.el as HostNode)
|
||||
if (parentSuspense.deps === 0) {
|
||||
parentSuspense.resolve()
|
||||
resolveSuspense(parentSuspense)
|
||||
}
|
||||
})
|
||||
// give it a placeholder
|
||||
@ -1621,7 +1632,7 @@ export function createRenderer<
|
||||
) {
|
||||
parentSuspense.deps--
|
||||
if (parentSuspense.deps === 0) {
|
||||
parentSuspense.resolve()
|
||||
resolveSuspense(parentSuspense)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { VNode, normalizeVNode } from './vnode'
|
||||
import { ShapeFlags } from '.'
|
||||
import { isFunction } from '@vue/shared'
|
||||
import { ComponentInternalInstance } from './component'
|
||||
|
||||
export const SuspenseSymbol = __DEV__ ? Symbol('Suspense key') : Symbol()
|
||||
|
||||
@ -11,33 +12,39 @@ export interface SuspenseBoundary<
|
||||
> {
|
||||
vnode: HostVNode
|
||||
parent: SuspenseBoundary<HostNode, HostElement> | null
|
||||
parentComponent: ComponentInternalInstance | null
|
||||
container: HostElement
|
||||
hiddenContainer: HostElement
|
||||
anchor: HostNode | null
|
||||
subTree: HostVNode
|
||||
fallbackTree: HostVNode
|
||||
deps: number
|
||||
isResolved: boolean
|
||||
isUnmounted: boolean
|
||||
effects: Function[]
|
||||
resolve(): void
|
||||
}
|
||||
|
||||
export function createSuspenseBoundary<HostNode, HostElement>(
|
||||
vnode: VNode<HostNode, HostElement>,
|
||||
parent: SuspenseBoundary<HostNode, HostElement> | null,
|
||||
parentComponent: ComponentInternalInstance | null,
|
||||
container: HostElement,
|
||||
resolve: () => void
|
||||
hiddenContainer: HostElement,
|
||||
anchor: HostNode | null
|
||||
): SuspenseBoundary<HostNode, HostElement> {
|
||||
return {
|
||||
vnode,
|
||||
parent,
|
||||
parentComponent,
|
||||
container,
|
||||
hiddenContainer,
|
||||
anchor,
|
||||
deps: 0,
|
||||
subTree: null as any, // will be set immediately after creation
|
||||
fallbackTree: null as any, // will be set immediately after creation
|
||||
isResolved: false,
|
||||
isUnmounted: false,
|
||||
effects: [],
|
||||
resolve
|
||||
effects: []
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user