Skip to content

Commit

Permalink
refactor: move scheduler types back to core
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Aug 19, 2024
1 parent ceedce4 commit 6f6e541
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 55 deletions.
5 changes: 2 additions & 3 deletions packages/reactivity/__tests__/watch.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import {
EffectScope,
type Ref,
type SchedulerJob,
WatchErrorCodes,
type WatchScheduler,
onWatcherCleanup,
ref,
watch,
} from '../src'

const queue: SchedulerJob[] = []
const queue: (() => void)[] = []

// a simple scheduler for testing purposes
let isFlushPending = false
Expand All @@ -19,7 +18,7 @@ const nextTick = (fn?: () => any) =>

const scheduler: WatchScheduler = (job, isFirstRun) => {
if (isFirstRun) {
job(true)
job()
} else {
queue.push(job)
flushJobs()
Expand Down
1 change: 0 additions & 1 deletion packages/reactivity/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,3 @@ export {
type WatchOptions,
type WatchScheduler,
} from './watch'
export { type SchedulerJob, SchedulerJobFlags } from './scheduler'
30 changes: 0 additions & 30 deletions packages/reactivity/src/scheduler.ts

This file was deleted.

14 changes: 8 additions & 6 deletions packages/reactivity/src/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
} from './effect'
import { isReactive, isShallow } from './reactive'
import { type Ref, isRef } from './ref'
import { type SchedulerJob, SchedulerJobFlags } from './scheduler'

// These errors were transferred from `packages/runtime-core/src/errorHandling.ts`
// to @vue/reactivity to allow co-location with the moved base watch logic, hence
Expand All @@ -48,14 +47,15 @@ export interface WatchOptions<Immediate = boolean> extends DebuggerOptions {
deep?: boolean | number
once?: boolean
scheduler?: WatchScheduler
augmentJob?: (job: (...args: any[]) => void) => void
onError?: HandleError
onWarn?: HandleWarn
}

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

export type WatchScheduler = (job: SchedulerJob, isFirstRun: boolean) => void
export type WatchScheduler = (job: () => void, isFirstRun: boolean) => void
export type HandleError = (err: unknown, type: WatchErrorCodes) => void
export type HandleWarn = (msg: string, ...args: any[]) => void

Expand Down Expand Up @@ -105,6 +105,7 @@ export function watch(
deep,
once,
scheduler,
augmentJob,
onWarn = __DEV__ ? warn : NOOP,
onError = DEFAULT_HANDLE_ERROR,
onTrack,
Expand Down Expand Up @@ -217,7 +218,8 @@ export function watch(
let oldValue: any = isMultiSource
? new Array((source as []).length).fill(INITIAL_WATCHER_VALUE)
: INITIAL_WATCHER_VALUE
const job: SchedulerJob = (immediateFirstRun?: boolean) => {

const job = (immediateFirstRun?: boolean) => {
if (
!(effect.flags & EffectFlags.ACTIVE) ||
(!effect.dirty && !immediateFirstRun)
Expand Down Expand Up @@ -267,9 +269,9 @@ export function watch(
}
}

// important: mark the job as a watcher callback so that scheduler knows
// it is allowed to self-trigger (#1727)
if (cb) job.flags! |= SchedulerJobFlags.ALLOW_RECURSE
if (augmentJob) {
augmentJob(job)
}

effect = new ReactiveEffect(getter)
if (scheduler) {
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime-core/__tests__/scheduler.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SchedulerJobFlags } from '@vue/reactivity'
import {
type SchedulerJob,
SchedulerJobFlags,
flushPostFlushCbs,
flushPreFlushCbs,
nextTick,
Expand Down
25 changes: 18 additions & 7 deletions packages/runtime-core/src/apiWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import {
type DebuggerOptions,
type ReactiveMarker,
type Ref,
SchedulerJobFlags,
type WatchErrorCodes,
watch as baseWatch,
getCurrentScope,
} from '@vue/reactivity'
import { type SchedulerJob, queueJob } from './scheduler'
import { type SchedulerJob, SchedulerJobFlags, queueJob } from './scheduler'
import {
EMPTY_OBJ,
NOOP,
Expand Down Expand Up @@ -211,26 +210,38 @@ function doWatch(
handleErrorWithInstance(err, instance, type)

// scheduler
let isPre = false
if (flush === 'post') {
baseWatchOptions.scheduler = job => {
queuePostRenderEffect(job, instance && instance.suspense)
}
} else if (flush !== 'sync') {
// default: 'pre'
isPre = true
baseWatchOptions.scheduler = (job, isFirstRun) => {
if (isFirstRun) {
job()
} else {
job.flags! |= SchedulerJobFlags.PRE
if (instance) {
job.id = instance.uid
;(job as SchedulerJob).i = instance
}
queueJob(job)
}
}
}

baseWatchOptions.augmentJob = (job: SchedulerJob) => {
// important: mark the job as a watcher callback so that scheduler knows
// it is allowed to self-trigger (#1727)
if (cb) {
job.flags! |= SchedulerJobFlags.ALLOW_RECURSE
}
if (isPre) {
job.flags! |= SchedulerJobFlags.PRE
if (instance) {
job.id = instance.uid
;(job as SchedulerJob).i = instance
}
}
}

const effect = baseWatch(source, cb, baseWatchOptions)
const scope = getCurrentScope()
const watchHandle: WatchHandle = () => {
Expand Down
3 changes: 2 additions & 1 deletion packages/runtime-core/src/components/BaseTransition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import {
} from '../vnode'
import { warn } from '../warning'
import { isKeepAlive } from './KeepAlive'
import { SchedulerJobFlags, toRaw } from '@vue/reactivity'
import { toRaw } from '@vue/reactivity'
import { ErrorCodes, callWithAsyncErrorHandling } from '../errorHandling'
import { PatchFlags, ShapeFlags, isArray, isFunction } from '@vue/shared'
import { onBeforeUnmount, onMounted } from '../apiLifecycle'
import { isTeleport } from './Teleport'
import type { RendererElement } from '../renderer'
import { SchedulerJobFlags } from '../scheduler'

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

Expand Down
2 changes: 1 addition & 1 deletion packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
} from '@vue/shared'
import {
type SchedulerJob,
SchedulerJobFlags,
type SchedulerJobs,
flushPostFlushCbs,
flushPreFlushCbs,
Expand All @@ -50,7 +51,6 @@ import {
import {
EffectFlags,
ReactiveEffect,
SchedulerJobFlags,
pauseTracking,
resetTracking,
} from '@vue/reactivity'
Expand Down
34 changes: 29 additions & 5 deletions packages/runtime-core/src/scheduler.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling'
import { type Awaited, NOOP, isArray } from '@vue/shared'
import { type ComponentInternalInstance, getComponentName } from './component'
import {
type SchedulerJob as BaseSchedulerJob,
SchedulerJobFlags,
} from '@vue/reactivity'

export interface SchedulerJob extends BaseSchedulerJob {
export enum SchedulerJobFlags {
QUEUED = 1 << 0,
PRE = 1 << 1,
/**
* Indicates whether the effect is allowed to recursively trigger itself
* when managed by the scheduler.
*
* By default, a job cannot trigger itself because some built-in method calls,
* e.g. Array.prototype.push actually performs reads as well (#1740) which
* can lead to confusing infinite loops.
* The allowed cases are component update functions and watch callbacks.
* Component update functions may update child component props, which in turn
* trigger flush: "pre" watch callbacks that mutates state that the parent
* relies on (#1801). Watch callbacks doesn't track its dependencies so if it
* triggers itself again, it's likely intentional and it is the user's
* responsibility to perform recursive state mutation that eventually
* stabilizes (#1727).
*/
ALLOW_RECURSE = 1 << 2,
DISPOSED = 1 << 3,
}

export interface SchedulerJob extends Function {
id?: number
/**
* flags can technically be undefined, but it can still be used in bitwise
* operations just like 0.
*/
flags?: SchedulerJobFlags
/**
* Attached by renderer.ts when setting up a component's render effect
* Used to obtain component information when reporting max recursive updates.
Expand Down

0 comments on commit 6f6e541

Please sign in to comment.