2024.05.14
vue 响应式实现(5)

按这个结构改造
src/effect.js和03中一样
import { ITERATE_KEY, TrackOpTypes } from '../utils/eunm.js'
// effect/track.js
import { activeEffect, targetMap } from './effect.js'
/**
* @type {boolean} 控制是否需要进行依赖收集
*/
let shouldTrack = true
export function pauseTracking() {
shouldTrack = false
}
export function enableTracking() {
shouldTrack = true
}
/**
* 依赖收集器
* @param target 原始对象
* @param type 操作类型
* @param key 操作的属性
*/
function track(target, type, key) {
if (!shouldTrack) {
return false
}
// 一层一层的查找,查找到后存储
let propMap = targetMap.get(target) if (!propMap) { targetMap.set(target, (propMap = new Map())) }
// 如果是遍历的话,key 是 undefined
if (type === TrackOpTypes.ITERATE) { key = ITERATE_KEY }
let typeMap = propMap.get(key) if (!typeMap) { propMap.set(key, (typeMap = new Map())) }
// 根据 type 值查找对应的 set
let depSet = typeMap.get(type) if (!depSet) { depSet = new Set() typeMap.set(type, depSet) }
// set 集合找到的话 存储依赖
if (!depSet.has(activeEffect)) { depSet.add(activeEffect) activeEffect.deps.push(depSet) }}
export { track }
import { ITERATE_KEY, TriggerOpTypes, triggerTypeMap } from '../utils/eunm.js'
import { activeEffect, targetMap } from './effect.js'
src / trigger.js
/**
*
* @param target 原始对象
* @param type 操作类型
* @param key 操作的属性
*/
function trigger(target, type, key) {
// 从设计好的数据结构里,一层一层的去找,找到对应的函数集合,然后全部执行一次
const effectFns = getEffectFn(target, type, key) if (!effectFns)
return for (const effectFn of effectFns) { if (effectFn === activeEffect)
continue effectFn() }}
/**
* 根据 target type key 信息找到对应的依赖集合
* @param target
* @param type
* @param key
*/
function getEffectFn(target, type, key) { const propMap = targetMap.get(target) if (!propMap)
return // 如果是新增或者删除,会涉及到触发额外的迭代
const keys = [key] if (type === TriggerOpTypes.ADD || type === TriggerOpTypes.DELETE) { keys.push(ITERATE_KEY) }
const effectFns = new Set() // 存储依赖的函数 for (const key of keys) { const typeMap = propMap.get(key) if (!typeMap)
continue
const trackTypes = triggerTypeMap[type] for (const trackType of trackTypes) { const dep = typeMap.get(trackType) if (!dep)
continue for (const effectFn of dep) { effectFns.add(effectFn) } } } return effectFns}
export { trigger }
懒执行
传入的effect的回调会自动执行,修改这种行为
改造 effect.js,给传递参数
export function effect(fn, options = {}) {
const { lazy } = options const environment = () => {
try {
activeEffect = environment
// 模拟真实的函数栈
effectStack.push(environment)
cleanup(environment)
return fn()
}
finally {
effectStack.pop()
activeEffect = effectStack[effectStack.length - 1]
}
}
environment.deps = [] // 记录该环境函数在哪些集合中使用
if (!lazy) { environment() } return environment}
如果传递了 lazy 返回函数交由控制权
手动派发更新
// effect.js
export function effect(fn, options = {}) {
const { lazy } = options const environment = () => {
try {
activeEffect = environment
// 模拟真实的函数栈
effectStack.push(environment)
cleanup(environment)
return fn()
}
finally {
effectStack.pop()
activeEffect = effectStack[effectStack.length - 1]
}
}
environment.deps = [] // 记录该环境函数在哪些集合中使用
environment.options = options if (!lazy) {
environment()
}
return environment
}
// trigger.js
function trigger(target, type, key) {
// 从设计好的数据结构里,一层一层的去找,找到对应的函数集合,然后全部执行一次
const effectFns = getEffectFn(target, type, key)
if (!effectFns)
return
for (const effectFn of effectFns) {
if (effectFn === activeEffect)
continue
// 如果传递了 scheduler ,交由外部手动更新
if (effectFn.options && effect.options.scheduler) { effect.options.scheduler(effectFn) } effectFn()
}
}