Skip to content

Commit dad9d0f

Browse files
committed
feat: scheduler in reactivity
1 parent 406c750 commit dad9d0f

File tree

8 files changed

+51
-75
lines changed

8 files changed

+51
-75
lines changed

packages/reactivity/__tests__/baseWatch.spec.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import type { Scheduler, SchedulerJob } from '../src/baseWatch'
21
import {
32
BaseWatchErrorCodes,
43
EffectScope,
54
type Ref,
5+
type SchedulerJob,
6+
type WatchScheduler,
67
baseWatch,
78
onWatcherCleanup,
89
ref,
@@ -15,7 +16,7 @@ let isFlushPending = false
1516
const resolvedPromise = /*#__PURE__*/ Promise.resolve() as Promise<any>
1617
const nextTick = (fn?: () => any) =>
1718
fn ? resolvedPromise.then(fn) : resolvedPromise
18-
const scheduler: Scheduler = (job, effect, immediateFirstRun, hasCb) => {
19+
const scheduler: WatchScheduler = (job, effect, immediateFirstRun, hasCb) => {
1920
if (immediateFirstRun) {
2021
!hasCb && effect.run()
2122
} else {

packages/reactivity/src/baseWatch.ts

+4-36
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
} from './effect'
2323
import { isReactive, isShallow } from './reactive'
2424
import { type Ref, isRef } from './ref'
25+
import { type SchedulerJob, SchedulerJobFlags } from './scheduler'
2526

2627
// These errors were transferred from `packages/runtime-core/src/errorHandling.ts`
2728
// along with baseWatch to maintain code compatibility. Hence,
@@ -32,39 +33,6 @@ export enum BaseWatchErrorCodes {
3233
WATCH_CLEANUP,
3334
}
3435

35-
// TODO move to a scheduler package
36-
enum SchedulerJobFlags {
37-
QUEUED = 1 << 0,
38-
PRE = 1 << 1,
39-
/**
40-
* Indicates whether the effect is allowed to recursively trigger itself
41-
* when managed by the scheduler.
42-
*
43-
* By default, a job cannot trigger itself because some built-in method calls,
44-
* e.g. Array.prototype.push actually performs reads as well (#1740) which
45-
* can lead to confusing infinite loops.
46-
* The allowed cases are component update functions and watch callbacks.
47-
* Component update functions may update child component props, which in turn
48-
* trigger flush: "pre" watch callbacks that mutates state that the parent
49-
* relies on (#1801). Watch callbacks doesn't track its dependencies so if it
50-
* triggers itself again, it's likely intentional and it is the user's
51-
* responsibility to perform recursive state mutation that eventually
52-
* stabilizes (#1727).
53-
*/
54-
ALLOW_RECURSE = 1 << 2,
55-
DISPOSED = 1 << 3,
56-
}
57-
58-
// TODO move to a scheduler package
59-
export interface SchedulerJob extends Function {
60-
id?: number
61-
/**
62-
* flags can technically be undefined, but it can still be used in bitwise
63-
* operations just like 0.
64-
*/
65-
flags?: SchedulerJobFlags
66-
}
67-
6836
type WatchEffect = (onCleanup: OnCleanup) => void
6937
type WatchSource<T = any> = Ref<T> | ComputedRef<T> | (() => T)
7038
type WatchCallback<V = any, OV = any> = (
@@ -78,15 +46,15 @@ export interface BaseWatchOptions<Immediate = boolean> extends DebuggerOptions {
7846
immediate?: Immediate
7947
deep?: boolean
8048
once?: boolean
81-
scheduler?: Scheduler
49+
scheduler?: WatchScheduler
8250
onError?: HandleError
8351
onWarn?: HandleWarn
8452
}
8553

8654
// initial value for watchers to trigger on undefined initial values
8755
const INITIAL_WATCHER_VALUE = {}
8856

89-
export type Scheduler = (
57+
export type WatchScheduler = (
9058
job: SchedulerJob,
9159
effect: ReactiveEffect,
9260
immediateFirstRun: boolean,
@@ -95,7 +63,7 @@ export type Scheduler = (
9563
export type HandleError = (err: unknown, type: BaseWatchErrorCodes) => void
9664
export type HandleWarn = (msg: string, ...args: any[]) => void
9765

98-
const DEFAULT_SCHEDULER: Scheduler = (
66+
const DEFAULT_SCHEDULER: WatchScheduler = (
9967
job,
10068
effect,
10169
immediateFirstRun,

packages/reactivity/src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,6 @@ export {
8585
onWatcherCleanup,
8686
BaseWatchErrorCodes,
8787
type BaseWatchOptions,
88-
type Scheduler,
88+
type WatchScheduler,
8989
} from './baseWatch'
90+
export { type SchedulerJob, SchedulerJobFlags } from './scheduler'

packages/reactivity/src/scheduler.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
export enum SchedulerJobFlags {
2+
QUEUED = 1 << 0,
3+
PRE = 1 << 1,
4+
/**
5+
* Indicates whether the effect is allowed to recursively trigger itself
6+
* when managed by the scheduler.
7+
*
8+
* By default, a job cannot trigger itself because some built-in method calls,
9+
* e.g. Array.prototype.push actually performs reads as well (#1740) which
10+
* can lead to confusing infinite loops.
11+
* The allowed cases are component update functions and watch callbacks.
12+
* Component update functions may update child component props, which in turn
13+
* trigger flush: "pre" watch callbacks that mutates state that the parent
14+
* relies on (#1801). Watch callbacks doesn't track its dependencies so if it
15+
* triggers itself again, it's likely intentional and it is the user's
16+
* responsibility to perform recursive state mutation that eventually
17+
* stabilizes (#1727).
18+
*/
19+
ALLOW_RECURSE = 1 << 2,
20+
DISPOSED = 1 << 3,
21+
}
22+
23+
export interface SchedulerJob extends Function {
24+
id?: number
25+
/**
26+
* flags can technically be undefined, but it can still be used in bitwise
27+
* operations just like 0.
28+
*/
29+
flags?: SchedulerJobFlags
30+
}

packages/runtime-core/__tests__/scheduler.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { SchedulerJobFlags } from '@vue/reactivity'
12
import {
23
type SchedulerJob,
3-
SchedulerJobFlags,
44
flushPostFlushCbs,
55
flushPreFlushCbs,
66
invalidateJob,

packages/runtime-core/src/components/BaseTransition.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@ import {
1414
} from '../vnode'
1515
import { warn } from '../warning'
1616
import { isKeepAlive } from './KeepAlive'
17-
import { toRaw } from '@vue/reactivity'
17+
import { SchedulerJobFlags, toRaw } from '@vue/reactivity'
1818
import { ErrorCodes, callWithAsyncErrorHandling } from '../errorHandling'
1919
import { PatchFlags, ShapeFlags, isArray } from '@vue/shared'
2020
import { onBeforeUnmount, onMounted } from '../apiLifecycle'
2121
import type { RendererElement } from '../renderer'
22-
import { SchedulerJobFlags } from '../scheduler'
2322

2423
type Hook<T = () => void> = T | T[]
2524

packages/runtime-core/src/renderer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import {
4040
import {
4141
type SchedulerFactory,
4242
type SchedulerJob,
43-
SchedulerJobFlags,
4443
flushPostFlushCbs,
4544
flushPreFlushCbs,
4645
invalidateJob,
@@ -50,6 +49,7 @@ import {
5049
import {
5150
EffectFlags,
5251
ReactiveEffect,
52+
SchedulerJobFlags,
5353
pauseTracking,
5454
resetTracking,
5555
} from '@vue/reactivity'

packages/runtime-core/src/scheduler.ts

+9-32
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,14 @@
11
import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling'
22
import { type Awaited, NOOP, isArray } from '@vue/shared'
33
import { type ComponentInternalInstance, getComponentName } from './component'
4-
import { EffectFlags, type Scheduler } from '@vue/reactivity'
5-
6-
export enum SchedulerJobFlags {
7-
QUEUED = 1 << 0,
8-
PRE = 1 << 1,
9-
/**
10-
* Indicates whether the effect is allowed to recursively trigger itself
11-
* when managed by the scheduler.
12-
*
13-
* By default, a job cannot trigger itself because some built-in method calls,
14-
* e.g. Array.prototype.push actually performs reads as well (#1740) which
15-
* can lead to confusing infinite loops.
16-
* The allowed cases are component update functions and watch callbacks.
17-
* Component update functions may update child component props, which in turn
18-
* trigger flush: "pre" watch callbacks that mutates state that the parent
19-
* relies on (#1801). Watch callbacks doesn't track its dependencies so if it
20-
* triggers itself again, it's likely intentional and it is the user's
21-
* responsibility to perform recursive state mutation that eventually
22-
* stabilizes (#1727).
23-
*/
24-
ALLOW_RECURSE = 1 << 2,
25-
DISPOSED = 1 << 3,
26-
}
27-
28-
export interface SchedulerJob extends Function {
29-
id?: number
30-
/**
31-
* flags can technically be undefined, but it can still be used in bitwise
32-
* operations just like 0.
33-
*/
34-
flags?: SchedulerJobFlags
4+
import {
5+
type SchedulerJob as BaseSchedulerJob,
6+
EffectFlags,
7+
SchedulerJobFlags,
8+
type WatchScheduler,
9+
} from '@vue/reactivity'
10+
11+
export interface SchedulerJob extends BaseSchedulerJob {
3512
/**
3613
* Attached by renderer.ts when setting up a component's render effect
3714
* Used to obtain component information when reporting max recursive updates.
@@ -301,7 +278,7 @@ function checkRecursiveUpdates(seen: CountMap, fn: SchedulerJob) {
301278

302279
export type SchedulerFactory = (
303280
instance: ComponentInternalInstance | null,
304-
) => Scheduler
281+
) => WatchScheduler
305282

306283
export const createSyncScheduler: SchedulerFactory =
307284
instance => (job, effect, immediateFirstRun, hasCb) => {

0 commit comments

Comments
 (0)