主题
new Dep()
提示
Dep
是整个 getter
依赖收集的核心
源码如下:
ts
import config from '../config'
import { DebuggerOptions, DebuggerEventExtraInfo } from 'v3'
let uid = 0
const pendingCleanupDeps: Dep[] = []
export const cleanupDeps = () => {
for (let i = 0; i < pendingCleanupDeps.length; i++) {
const dep = pendingCleanupDeps[i]
dep.subs = dep.subs.filter(s => s)
dep._pending = false
}
pendingCleanupDeps.length = 0
}
export default class Dep {
static target?: DepTarget | null
id: number
subs: Array<DepTarget | null>
// pending subs cleanup
_pending = false
constructor() {
this.id = uid++
this.subs = []
}
addSub(sub: DepTarget) {
this.subs.push(sub)
}
removeSub(sub: DepTarget) {
// #12696 deps with massive amount of subscribers are extremely slow to clean up in Chromium to workaround this, we unset the sub for now, and clear them on next scheduler flush.
// #12696 具有大量订阅者的 deps 在 Chromium 中清理起来非常慢,为了解决这个问题,我们暂时取消设置 sub,并在下一次调度程序刷新时清除它们
this.subs[this.subs.indexOf(sub)] = null
if (!this._pending) {
this._pending = true
pendingCleanupDeps.push(this)
}
}
depend(info?: DebuggerEventExtraInfo) {
if (Dep.target) {
Dep.target.addDep(this)
if (__DEV__ && info && Dep.target.onTrack) {
Dep.target.onTrack({
effect: Dep.target,
...info
})
}
}
}
notify(info?: DebuggerEventExtraInfo) {
// stabilize the subscriber list first
const subs = this.subs.filter(s => s) as DepTarget[]
if (__DEV__ && !config.async) {
// subs aren't sorted in scheduler if not running async we need to sort them now to make sure they fire in correct order
subs.sort((a, b) => a.id - b.id)
}
for (let i = 0, l = subs.length; i < l; i++) {
const sub = subs[i]
if (__DEV__ && info) {
sub.onTrigger &&
sub.onTrigger({
effect: subs[i],
...info
})
}
sub.update()
}
}
}
// The current target watcher being evaluated.
// This is globally unique because only one watcher
// can be evaluated at a time.
Dep.target = null
const targetStack: Array<DepTarget | null | undefined> = []
export function pushTarget(target?: DepTarget | null) {
targetStack.push(target)
Dep.target = target
}
export function popTarget() {
targetStack.pop()
Dep.target = targetStack[targetStack.length - 1]
}
Dep
类上有一个静态属性target
, 这是一个全局唯一 Watcher
,这是一个非常巧妙的设, 因为在同一时间只能有一个全局的 Watcher
被计算,另外它的自身属性 subs
也是 Watcher
的数组。
Dep
实际上就是对 Watcher
的一种管理,Dep
脱离 Watcher
单独存在是没有意义的,为了完整地讲清楚依赖收集过程,我们有必要看一下 Watcher
的一些相关实现