refactor: move resolveSuspense out
This commit is contained in:
parent
6dc91971d1
commit
bbc3442c52
@ -286,7 +286,7 @@ describe('renderer: suspense', () => {
|
|||||||
expect(calls).toEqual([])
|
expect(calls).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
test.todo('unmount suspense after resolve')
|
test('unmount suspense after resolve', () => {})
|
||||||
|
|
||||||
test.todo('unmount suspense before resolve')
|
test.todo('unmount suspense before resolve')
|
||||||
|
|
||||||
|
@ -721,63 +721,16 @@ export function createRenderer<
|
|||||||
isSVG: boolean,
|
isSVG: boolean,
|
||||||
optimized: boolean
|
optimized: boolean
|
||||||
) {
|
) {
|
||||||
|
const hiddenContainer = hostCreateElement('div')
|
||||||
const suspense = (n2.suspense = createSuspenseBoundary(
|
const suspense = (n2.suspense = createSuspenseBoundary(
|
||||||
n2,
|
n2,
|
||||||
parentSuspense,
|
parentSuspense,
|
||||||
hostCreateElement('div'),
|
parentComponent,
|
||||||
resolveSuspense
|
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)
|
const { content, fallback } = normalizeSuspenseChildren(n2)
|
||||||
suspense.subTree = content
|
suspense.subTree = content
|
||||||
suspense.fallbackTree = fallback
|
suspense.fallbackTree = fallback
|
||||||
@ -786,7 +739,7 @@ export function createRenderer<
|
|||||||
patch(
|
patch(
|
||||||
null,
|
null,
|
||||||
content,
|
content,
|
||||||
suspense.container,
|
hiddenContainer,
|
||||||
null,
|
null,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
@ -809,7 +762,7 @@ export function createRenderer<
|
|||||||
n2.el = fallback.el
|
n2.el = fallback.el
|
||||||
} else {
|
} else {
|
||||||
// Suspense has no async deps. Just resolve.
|
// Suspense has no async deps. Just resolve.
|
||||||
suspense.resolve()
|
resolveSuspense(suspense)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -831,7 +784,7 @@ export function createRenderer<
|
|||||||
patch(
|
patch(
|
||||||
oldSubTree,
|
oldSubTree,
|
||||||
content,
|
content,
|
||||||
suspense.container,
|
suspense.hiddenContainer,
|
||||||
null,
|
null,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
suspense,
|
suspense,
|
||||||
@ -873,6 +826,64 @@ export function createRenderer<
|
|||||||
suspense.fallbackTree = fallback
|
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(
|
function processComponent(
|
||||||
n1: HostVNode | null,
|
n1: HostVNode | null,
|
||||||
n2: HostVNode,
|
n2: HostVNode,
|
||||||
@ -992,7 +1003,7 @@ export function createRenderer<
|
|||||||
)
|
)
|
||||||
updateHOCHostEl(instance, initialVNode.el as HostNode)
|
updateHOCHostEl(instance, initialVNode.el as HostNode)
|
||||||
if (parentSuspense.deps === 0) {
|
if (parentSuspense.deps === 0) {
|
||||||
parentSuspense.resolve()
|
resolveSuspense(parentSuspense)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// give it a placeholder
|
// give it a placeholder
|
||||||
@ -1621,7 +1632,7 @@ export function createRenderer<
|
|||||||
) {
|
) {
|
||||||
parentSuspense.deps--
|
parentSuspense.deps--
|
||||||
if (parentSuspense.deps === 0) {
|
if (parentSuspense.deps === 0) {
|
||||||
parentSuspense.resolve()
|
resolveSuspense(parentSuspense)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { VNode, normalizeVNode } from './vnode'
|
import { VNode, normalizeVNode } from './vnode'
|
||||||
import { ShapeFlags } from '.'
|
import { ShapeFlags } from '.'
|
||||||
import { isFunction } from '@vue/shared'
|
import { isFunction } from '@vue/shared'
|
||||||
|
import { ComponentInternalInstance } from './component'
|
||||||
|
|
||||||
export const SuspenseSymbol = __DEV__ ? Symbol('Suspense key') : Symbol()
|
export const SuspenseSymbol = __DEV__ ? Symbol('Suspense key') : Symbol()
|
||||||
|
|
||||||
@ -11,33 +12,39 @@ export interface SuspenseBoundary<
|
|||||||
> {
|
> {
|
||||||
vnode: HostVNode
|
vnode: HostVNode
|
||||||
parent: SuspenseBoundary<HostNode, HostElement> | null
|
parent: SuspenseBoundary<HostNode, HostElement> | null
|
||||||
|
parentComponent: ComponentInternalInstance | null
|
||||||
container: HostElement
|
container: HostElement
|
||||||
|
hiddenContainer: HostElement
|
||||||
|
anchor: HostNode | null
|
||||||
subTree: HostVNode
|
subTree: HostVNode
|
||||||
fallbackTree: HostVNode
|
fallbackTree: HostVNode
|
||||||
deps: number
|
deps: number
|
||||||
isResolved: boolean
|
isResolved: boolean
|
||||||
isUnmounted: boolean
|
isUnmounted: boolean
|
||||||
effects: Function[]
|
effects: Function[]
|
||||||
resolve(): void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createSuspenseBoundary<HostNode, HostElement>(
|
export function createSuspenseBoundary<HostNode, HostElement>(
|
||||||
vnode: VNode<HostNode, HostElement>,
|
vnode: VNode<HostNode, HostElement>,
|
||||||
parent: SuspenseBoundary<HostNode, HostElement> | null,
|
parent: SuspenseBoundary<HostNode, HostElement> | null,
|
||||||
|
parentComponent: ComponentInternalInstance | null,
|
||||||
container: HostElement,
|
container: HostElement,
|
||||||
resolve: () => void
|
hiddenContainer: HostElement,
|
||||||
|
anchor: HostNode | null
|
||||||
): SuspenseBoundary<HostNode, HostElement> {
|
): SuspenseBoundary<HostNode, HostElement> {
|
||||||
return {
|
return {
|
||||||
vnode,
|
vnode,
|
||||||
parent,
|
parent,
|
||||||
|
parentComponent,
|
||||||
container,
|
container,
|
||||||
|
hiddenContainer,
|
||||||
|
anchor,
|
||||||
deps: 0,
|
deps: 0,
|
||||||
subTree: null as any, // will be set immediately after creation
|
subTree: null as any, // will be set immediately after creation
|
||||||
fallbackTree: null as any, // will be set immediately after creation
|
fallbackTree: null as any, // will be set immediately after creation
|
||||||
isResolved: false,
|
isResolved: false,
|
||||||
isUnmounted: false,
|
isUnmounted: false,
|
||||||
effects: [],
|
effects: []
|
||||||
resolve
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user