https://github.com/vuejs/vue-next/blob/master/packages/runtime-core/src/apiWatch.ts
目录
Watch
@/packages/runtime-core/src/apiWatch.ts
watch.dot
https://github.com/vuejs/vue-next/blob/master/packages/runtime-core/src/apiWatch.ts
Watch
@/packages/runtime-core/src/apiWatch.ts
watch和watchEffect都是在调用doWatch函数,所以文核心就是doWatch函数
export function watchEffect(
effect: WatchEffect,
options?: WatchOptionsBase
){
return doWatch(effect, null, options)
}
export function watchPostEffect(
effect: WatchEffect,
options?: DebuggerOptions
){
options.plush = 'post'
return doWatch(effect, null, options)
}
export function watchSyncEffect(
effect: WatchEffect,
options?: DebuggerOptions
){
options.plush = 'sync'
return doWatch(effect, null, options)
}
// 上面几个函数都指向doWatch()
// 对watch函数进行重载,4次
export function watch<
T extends MultiWatchSources,
Immediate extends Readonly<boolean> = false
>(
sources:[...T],
cb: WatchCallback<MapSources<T,false>,MapSources<T,Immediate>>,
options?: WatchOptions<Immediate>
): WatchStopHandle
// ...
export function watch<
T = any,
Immediate extends Readonly<boolean> = false
>(
sources: T | WatchSource<T>,
cb: any,
options?: WatchOptions<Immediate>
): WatchStopHandle {
return doWatch(source as any, cb, options)
}
// 核心函数 doWatch
function doWatch(
// source:
// WatchSource是个ref
// WatchEffect是个副作用
// cb:
// watch独有的,watchEffect时是null
source: WatchSource | WatchSource[] | WatchEffect | object,
cb: WatchCallback | null,
{ immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
): WatchStopHandle {
let getter:()=> any // 获取值
// 会有不同的回调
if(isRef(source)) {
getter = () => source.value
} else if (isReactive(spurce)) {
getter = () => source
} else if (isArray(source)) {
getter = () =>
source.map(s => {
if(isRef(s)) {
return s.value
} else if (isReactive(s)) {
return traverse(s)
} else if (isFunction(s)) {
// 报错
return callWithErrorHandling(s, instance, ErrorCodes.WARCH_GETTER)
} else {
__DEV__ && warnInvalidSource(s) // 报错
}
})
} else if (isFunction(source)) {
if(cb) {
// watch
} else {
// watchEffect
}
}
// ...
// job是effect具体要做的事情
const job: SchedulerJob = () => {
if(cb) {
// watch(source, cb)
const newValue = effect.run() // 执行一下,拿到新的值 ,基于getter拿到的effect
// 一些验证条件,通过之后会执行cb
// if...
// if.... hasChanged(newValue, oldValue) // 发送变化才执行
callWithAsyncErrorHandling(cb, ...)
}
}
let scheduler: EffectScheduler
if (flush === 'sync') {
scheduler = job as any // 直接调用调度程序函数
} else if (flush === 'post') {
// 放队列里,一项一项执行
scheduler = () => queuePostRenderEffect(job, instance && instance.suspense)
} else {
// default: 'pre' //也放到一个队列里
scheduler = () => {
if (!instance || instance.isMounted) {
queuePreFlushCb(job)
} else {
// 使用“pre”选项,第一次呼叫必须在
// 组件已安装,因此可以同步调用它。
job()
}
}
}
// new 一个 effect;scheduler:控制执行时机,实际执行的就是scheduler
const effect = new ReactiveEffect(getter, scheduler)
}
watch.dot
digraph {
watchEffect -> doWatch;
watch -> doWatch;
doWatch -> reactiveWrapper -> initialGet;
activeEffect[color=green]
reactiveWrapper -> activeEffect[dir=none]
initialGet -> trackAll_refs_reactives
trigger -> activeEffect -> job
}
// dot language
// graphviz