Skip to content

Commit 90610e3

Browse files
committed
feat: make effectScope compatible with async context
1 parent b845df7 commit 90610e3

File tree

5 files changed

+51
-33
lines changed

5 files changed

+51
-33
lines changed

packages/reactivity/src/effectScope.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,30 @@ export class EffectScope {
1818
run<T>(fn: () => T): T | undefined {
1919
if (this.active) {
2020
try {
21-
effectScopeStack.push(this)
22-
activeEffectScope = this
21+
this.on()
2322
return fn()
2423
} finally {
25-
effectScopeStack.pop()
26-
activeEffectScope = effectScopeStack[effectScopeStack.length - 1]
24+
this.off()
2725
}
2826
} else if (__DEV__) {
2927
warn(`cannot run an inactive effect scope.`)
3028
}
3129
}
3230

31+
on() {
32+
if (this.active) {
33+
effectScopeStack.push(this)
34+
activeEffectScope = this
35+
}
36+
}
37+
38+
off() {
39+
if (this.active) {
40+
effectScopeStack.pop()
41+
activeEffectScope = effectScopeStack[effectScopeStack.length - 1]
42+
}
43+
}
44+
3345
stop() {
3446
if (this.active) {
3547
this.effects.forEach(e => e.stop())

packages/runtime-core/src/apiLifecycle.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {
33
currentInstance,
44
isInSSRComponentSetup,
55
LifecycleHooks,
6-
setCurrentInstance
6+
setCurrentInstance,
7+
unsetCurrentInstance
78
} from './component'
89
import { ComponentPublicInstance } from './componentPublicInstance'
910
import { callWithAsyncErrorHandling, ErrorTypeStrings } from './errorHandling'
@@ -37,12 +38,8 @@ export function injectHook(
3738
// This assumes the hook does not synchronously trigger other hooks, which
3839
// can only be false when the user does something really funky.
3940
setCurrentInstance(target)
40-
const res = target.scope.active
41-
? target.scope.run(() =>
42-
callWithAsyncErrorHandling(hook, target, type, args)
43-
)
44-
: callWithAsyncErrorHandling(hook, target, type, args)
45-
setCurrentInstance(null)
41+
const res = callWithAsyncErrorHandling(hook, target, type, args)
42+
unsetCurrentInstance()
4643
resetTracking()
4744
return res
4845
})

packages/runtime-core/src/apiSetupHelpers.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {
33
getCurrentInstance,
44
setCurrentInstance,
55
SetupContext,
6-
createSetupContext
6+
createSetupContext,
7+
unsetCurrentInstance
78
} from './component'
89
import { EmitFn, EmitsOptions } from './componentEmits'
910
import {
@@ -248,9 +249,15 @@ export function mergeDefaults(
248249
* @internal
249250
*/
250251
export function withAsyncContext(getAwaitable: () => any) {
251-
const ctx = getCurrentInstance()
252+
const ctx = getCurrentInstance()!
253+
if (__DEV__ && !ctx) {
254+
warn(
255+
`withAsyncContext called without active current instance. ` +
256+
`This is likely a bug.`
257+
)
258+
}
252259
let awaitable = getAwaitable()
253-
setCurrentInstance(null)
260+
unsetCurrentInstance()
254261
if (isPromise(awaitable)) {
255262
awaitable = awaitable.catch(e => {
256263
setCurrentInstance(ctx)

packages/runtime-core/src/component.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -527,10 +527,14 @@ export let currentInstance: ComponentInternalInstance | null = null
527527
export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
528528
currentInstance || currentRenderingInstance
529529

530-
export const setCurrentInstance = (
531-
instance: ComponentInternalInstance | null
532-
) => {
530+
export const setCurrentInstance = (instance: ComponentInternalInstance) => {
533531
currentInstance = instance
532+
instance.scope.on()
533+
}
534+
535+
export const unsetCurrentInstance = () => {
536+
currentInstance && currentInstance.scope.off()
537+
currentInstance = null
534538
}
535539

536540
const isBuiltInTag = /*#__PURE__*/ makeMap('slot,component')
@@ -612,22 +616,19 @@ function setupStatefulComponent(
612616
const setupContext = (instance.setupContext =
613617
setup.length > 1 ? createSetupContext(instance) : null)
614618

615-
currentInstance = instance
619+
setCurrentInstance(instance)
616620
pauseTracking()
617-
const setupResult = instance.scope.run(() =>
618-
callWithErrorHandling(setup, instance, ErrorCodes.SETUP_FUNCTION, [
619-
__DEV__ ? shallowReadonly(instance.props) : instance.props,
620-
setupContext
621-
])
621+
const setupResult = callWithErrorHandling(
622+
setup,
623+
instance,
624+
ErrorCodes.SETUP_FUNCTION,
625+
[__DEV__ ? shallowReadonly(instance.props) : instance.props, setupContext]
622626
)
623627
resetTracking()
624-
currentInstance = null
628+
unsetCurrentInstance()
625629

626630
if (isPromise(setupResult)) {
627-
const unsetInstance = () => {
628-
currentInstance = null
629-
}
630-
setupResult.then(unsetInstance, unsetInstance)
631+
setupResult.then(unsetCurrentInstance, unsetCurrentInstance)
631632

632633
if (isSSR) {
633634
// return the promise so server-renderer can wait on it
@@ -795,11 +796,11 @@ export function finishComponentSetup(
795796

796797
// support for 2.x options
797798
if (__FEATURE_OPTIONS_API__ && !(__COMPAT__ && skipOptions)) {
798-
currentInstance = instance
799+
setCurrentInstance(instance)
799800
pauseTracking()
800-
instance.scope.run(() => applyOptions(instance))
801+
applyOptions(instance)
801802
resetTracking()
802-
currentInstance = null
803+
unsetCurrentInstance()
803804
}
804805

805806
// warn missing template/render

packages/runtime-core/src/componentProps.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ import {
2929
ComponentInternalInstance,
3030
ComponentOptions,
3131
ConcreteComponent,
32-
setCurrentInstance
32+
setCurrentInstance,
33+
unsetCurrentInstance
3334
} from './component'
3435
import { isEmitListener } from './componentEmits'
3536
import { InternalObjectKey } from './vnode'
@@ -411,7 +412,7 @@ function resolvePropValue(
411412
: null,
412413
props
413414
)
414-
setCurrentInstance(null)
415+
unsetCurrentInstance()
415416
}
416417
} else {
417418
value = defaultValue

0 commit comments

Comments
 (0)