说明
- 本文主要探讨createDep、initDepMarkers、finalizeDepMarkers、wasTracked、newTracked方法中dep.n、dep.w变化,省略了非必要的代码
调试源码用例
import { reactive, effect,readonly,isReactive } from './reactivity.esm-browser.js'
const state = reactive({flag: true, age:10,name:'wl'})
effect(()=>{
state.flag ? state.age: state.name;
})
state.flag = false;
关键步骤
effect 函数
export function effect(fn) {
const _effect = new ReactiveEffect(fn)
_effect.run()
}
run函数
run() {
try {
this.parent = activeEffect
activeEffect = this
trackOpBit = 1 << ++effectTrackDepth
if (effectTrackDepth <= maxMarkerBits) {
initDepMarkers(this)
}
return this.fn()
} finally {
if (effectTrackDepth <= maxMarkerBits) {
finalizeDepMarkers(this)
}
trackOpBit = 1 << --effectTrackDepth
activeEffect = this.parent
this.parent = undefined
}
}
initDepMarkers函数
export const initDepMarkers = ({ deps }) => {
if (deps.length) {
for (let i = 0; i < deps.length; i++) {
deps[i].w |= trackOpBit
}
}
}
track函数
export function track(target, type, key) {
if (shouldTrack && activeEffect) {
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = createDep()))
}
trackEffects(dep)
}
}
trackEffects 函数
export function trackEffects(dep) {
let shouldTrack = false
if (effectTrackDepth <= maxMarkerBits) {
if (!newTracked(dep)) {
dep.n |= trackOpBit
shouldTrack = !wasTracked(dep)
}
}
if (shouldTrack) {
dep.add(activeEffect!)
activeEffect!.deps.push(dep)
}
}
export const newTracked = (dep: Dep): boolean => (dep.n & trackOpBit) > 0
export const wasTracked = (dep: Dep): boolean => (dep.w & trackOpBit) > 0
- _effect.run()执行run方法,effectTrackDepth为0的全局变量,trackOpBit = 1 << ++effectTrackDepth后,trackOpBit是2 (base 10),00000000 00000000 00000000 00000010 (base 2) 接着执行initDepMarkers(this),此时的this.deps.length ===0 ,就直接跳过,开始执行this.fn进行依赖收集. 会惊醒收集flag,age 这个连个属性。
- state.flag取值,接着执行track方法,初始化会执行createDep 创建dep,此时的dep.w === 0,dep.n ===0.
- 执行trackEffects(dep),执行newTracked(dep),dep.n === 0, newTracked(dep)返回false。注意:effect回调中用到属性都会进入这个判断分支。同理,此时wasTracked(dep)也是false,shouldTrack为true.
- 总结:此时的state.flag对应的dep.n = 2 即0000 0010, dep.w = 0即0000 0000.同理state.age对应的dep.n = 2 即(0000 0010),dep.w = 0即 0000 0000.此activeEffect.deps= [dep1,dep2] dep1,dep2分别是flag,age对应的dep.
- this.fn执行完,执行finalizeDepMarkers(this),wasTracked(dep)返回false,
- 总结:此时两个dep中, dep.n dep.w 都是0. activeEffect.deps= [dep1,dep2]
export const finalizeDepMarkers = (effect: ReactiveEffect) => {
const { deps } = effect
if (deps.length) {
let ptr = 0
for (let i = 0; i < deps.length; i++) {
const dep = deps[i]
if (wasTracked(dep) && !newTracked(dep)) {
dep.delete(effect)
} else {
deps[ptr++] = dep
}
dep.w &= ~trackOpBit
dep.n &= ~trackOpBit
}
deps.length = ptr
}
}
改变flag为false
export function triggerEffects(dep) {
const effects = isArray(dep) ? dep : [...dep]
for (const effect of effects) {
triggerEffect(effect)
}
}
function triggerEffect(effect) {
effect.run()
}
export const initDepMarkers = ({ deps }: ReactiveEffect) => {
if (deps.length) {
for (let i = 0; i < deps.length; i++) {
deps[i].w |= trackOpBit
}
}
}
- 再次执行run方法,trackOpBit = 1 << ++effectTrackDepth后,trackOpBit是2 (base 10),00000000 00000000 00000000 00000010 (base 2) ,执行initDepMarkers(this),将activeEffect.deps= [dep1,dep2]中的两个dep的dep.w = 2
- 执行this.fn收集依赖,此时收集的flag,name两个属性,
- 收集flag时,此时targetMap中存储着flag对应的dep,不需要执行createDep,接着执行下边代码.执行完下边代码shouldTrack是false,不用在进行依赖收集,即flag在更新前后都在effect中使用
- 此时flag对应的dep.w === 2,dep.n === 2
- 收集name的依赖,targetMap中不存在name对应的dep,创建性的dep即dep.n === 0、dep.w === 0,执行代码块1后,name对应的dep.n===2,shouldTrack=== true,将此dep添加到activeEffect.deps中。
- 总结:此时activeEffect.deps= [dep1,dep2,dep3]
- dep1: 对应flag dep.n === 2 dep.w === 2
- dep2: 对应age dep.n === 0 dep.w === 2
- dep3: 对应name dep.n ===2 dep.w === 0
- 执行完this.fn,执行finalizeDepMarkers,此时age对应的dep中删除此activeEffect,重置dep.n === dep.w ===0.
- name对应的dep覆盖activeEffect.deps[1]中元素,重置dep.n === dep.w ===0.
- 总结:此时activeEffect.deps= [dep1,dep3]
if (!newTracked(dep)) {
dep.n |= trackOpBit
shouldTrack = !wasTracked(dep)
}
总结:dep.n、dep.w变化过程
- 初始化
| 标题 | flag dep1| age dep2 | name dep3 | activeEffect.deps |
| --- | --- | --- | --- | ---|
| 初始化 | n:0 w:0 | n:0 w:0 | |
| this.fn后 | n:2 w:0 | n:2 w:0 | | [dep1,dep2] |
| finalizeDepMarkers | n:0 w:0 | n:0 w:0 | | [dep1,dep2] |
- 改变flag再次执行run
| 标题 | flag dep1| age dep2 | name dep3 | activeEffect.deps |
| --- | --- | --- | --- | ---|
| initDepMarkers | n:0 w:2 | n:0 w:2 | | dep1,dep2] |
| this.fn后 | n:2 w:2 | n:0 w:2 | n:2 w:0 | [dep1,dep2,dep3] |
| finalizeDepMarkers | n:0 w:0 | n:0 w:0 | n:0 w:0 | [dep1,dep3] |
- age的dep2中删除此activeEffect。