arrayInstrumentations主要是改写数组的方法
1.改写includes、indexOf、lastIndexOf这三个方法。这三个方法无法'准确'追踪数组中元素。具体表现如下(案例来自网络)
const arr = reactive([2,1,3])
effect(() => {
console.log(arr.indexOf(2))
})
setTimeout(() =>{
arr[1] = 4
}, 5000)
当修改arr[1]的值时,将会触发副作用函数的的执行,但arr[1]值的改变并不会影响副作用函数的结果(arr[0]不等于2时才影响),因此可以判定是无效的触发。
因此当调用的是这三个方法时,要对数组中的每个元素进行依赖收集,这样才能正确触发,这里还要注意处理参数已经被proxy代理的情况
;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => {
instrumentations[key] = function (this: unknown[], ...args: unknown[]) {
const arr = toRaw(this) as any
for (let i = 0, l = this.length; i < l; i++) {
track(arr, TrackOpTypes.GET, i + '')
}
// we run the method using the original args first (which may be reactive)
const res = arr[key](...args)
if (res === -1 || res === false) {
// if that didn't work, run it again using raw values.
return arr[key](...args.map(toRaw))
} else {
return res
}
}
})
2.改写push、pop、shift、unshift、splice这三个方法。这三个方法是直接调用数组对应的方法,返回对应的结果,不进行额外的依赖收集
// instrument length-altering mutation methods to avoid length being tracked
// which leads to infinite loops in some cases (#2137)
;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
instrumentations[key] = function (this: unknown[], ...args: unknown[]) {
pauseTracking()
const res = (toRaw(this) as any)[key].apply(this, args)
resetTracking()
return res
}
})
export function pauseTracking() {
trackStack.push(shouldTrack)
shouldTrack = false
}
export function resetTracking() {
const last = trackStack.pop()
shouldTrack = last === undefined ? true : last
}
为什么这么做呢?从注释中找到的信息是避免length改变陷入无尽的回调。那么如果此处不进行依赖收集,那么依赖收集是在哪一块进行的呢?让我们回看上一章中mutableHandlers方法,此方法只是针对数组这八个方法进行改写,那么length属性呢,不在这当中,还是继续往下执行,会进行依赖收集。因此如果这里再进行依赖收集,那么就会重复,因此不需要再进行收集。
下文主要对依赖收集函数track进行展开!
本人菜鸡,有问题望前辈及时指出,不胜感激!!