无限极服务
146.43MB · 2025-10-24
在 Vue3 的响应式系统中,有两个重要的角色——depsLength 和 trackId。
reactive() 或 ref() 创建effect() 在依赖的响应式数据变化时,重新执行trackId 是一个自增的唯一标识,用来确定副作用的一次特定运行周期。这样的话,每次执行副作用都会是一个新的身份号码
class ReactiveEffect {
private _trackId = 0
...
run() {
// 每次运行都++,每次都是不一样的
this._trackId++
// ...执行副作用函数
}
}
depsLength 用于记录当前副作用实际使用的依赖数量,也就是deps中真正需要使用的数量
class ReactiveEffect {
deps = [] // 所有依赖的集合
depsLength = 0 // 当前有效依赖的数量
}
例子:
const state = reactive({ a: 1, b: 2, c: 3, d: 4, e: 5 })
// 第一次执行:依赖所有5个属性
effect(() => {
console.log(state.a, state.b, state.c, state.d, state.e)
})
第一次运行后的状态: deps收集了5个依赖,depsLength++了5次所以是5,trackId第一次执行因为effect是第一次运行
effect.deps = [dep_a, dep_b, dep_c, dep_d, dep_e]effect.depsLength = 5effect.trackId = 1现在条件发生变化,副作用只需要部分依赖:
// 条件改变,第二次运行:只依赖a和b
effect(() => {
if (true) {
console.log(state.a, state.b) // 只依赖a, b
} else {
console.log(state.c, state.d, state.e)
}
})
在副作用重新执行前,Vue 会进行预清理:
function preCleanupEffect(effect: ReactiveEffect) {
effect.depsLength = 0 // 重置水位线,从第一个开始
effect.trackId++ // 换发新身份证
}
此时状态变为:
effect.deps = [dep_a, dep_b, dep_c, dep_d, dep_e] (保持不变)effect.depsLength = 0 (重置)effect.trackId = 2 (更新)清理后开始进行依赖收集
function trackEffects(effect,dep) {
//trackId不一样说明周期不一样,不一样就set进去
//现在是第二次,trackId为2,而dep.get(effect)<上一次的trackId>是1
if (dep.get(effect) !== effect._trackId) {
dep.set(effect, effect._trackId)
}
//拿到effect中的现在下标的dep,也就是老dep
let oldDep = effect.deps[effect._depsLenght]
//老dep与新dep不相同,说明是新添加的依赖、
//如果是第一次oldDep就是undefined
if (oldDep !== dep) {
//因为老的变了,自然要把老的给清理掉,留着也没用
if(oldDep){
cleanDepEffect(oldDep, effect)
}
//无论老的有没有,只要是不同,就要把新的dep添加进去
effect.deps[effect._depsLenght++] = dep;
}else{
//这里是复用的情况,++下次进行判断下一个
effect._depsLenght++;
}
}
function cleanDepEffect(oldDep, dep) {
//从旧的dep中删除effect
dep.delete(oldDep)
//如果dep已经没有effect了,就执行cleanup函数,从映射表中删除该key对应的dep
if(dep.size === 0){
dep.cleanup()
}
}
在我们的例子中:
state.a → 复用 deps[0] 存放 dep_a,depsLength = 1state.b → 复用 deps[1] 存放 dep_b,depsLength = 2此时状态:
effect.deps = [dep_a, dep_b, dep_c, dep_d, dep_e] (前两个被复用,但c,d,e还在,它们已经是多余的了要删掉)effect.depsLength = 2effect.trackId = 2清理多余的依赖:
function finalizeDepMarkers(effect: ReactiveEffect) {
const { deps, depsLength } = effect
//因为上一步的操作中无论是复用或者是替换都会把desLength推到最新数量的位置
//因此如果deps[]的长度大于desLength,则都是多余的了
if (depsLength < deps.length) {
for (let i = depsLength; i < deps.length; i++) {
const dep = deps[i]
if (dep) {
// 从依赖集合中移除这个effect
cleanUpDepEffect(dep, effect)
// 清空数组引用
deps[i] = null!
}
}
// 最后把deps[]的数组长度调整到最新的长度
deps.length = depsLength
}
}
function cleanUpDepEffect(dep: Dep, effect: ReactiveEffect) {
dep.delete(effect) // 从dep的集合中移除effect
}
现在的操作:
dep_c、dep_d、dep_edeps.length = 2最终状态:
effect.deps = [dep_a, dep_b] (修改后的deps)effect.depsLength = 2effect.trackId = 2两者相辅相成,两个小小的number保证了响应式系统的准确和效率
tarckId:是周期的唯一标识,用于防止重复收集依赖depsLength:记录当前的deps的位置,在清理dep上起到重要作用
2025-10-25
2025/26 冬春航季即将启动,国航 C919 新增广州、西安、长沙等新航点
部分 Win11 23H2,Windows Server 2016/2022 安装微软 10 月累积更新失败,严重至“变砖”