feat(effects): 实现响应式依赖收集和触发机制

- 创建targetMap WeakMap用于存储响应式对象及其依赖映射关系
- 实现track函数用于收集依赖并建立target-key-effect的映射
- 实现trigger函数用于触发指定key的依赖更新
- 在track中通过activeEffect判断是否需要收集依赖
- 添加详细的JSDoc注释说明参数和功能
- 示例页面中添加定时器验证响应式更新效果
This commit is contained in:
dj
2026-02-04 22:19:55 +08:00
parent 5a24b61edf
commit 0850e05bd1
2 changed files with 39 additions and 7 deletions

View File

@@ -1,3 +1,13 @@
type KeyToDepMap = Map<any, ReactiveEffect>
/**
* 收集所有依赖的WeakMap实例
* key: 响应性对象
* value: Map对象
* key: 响应性对象的指定属性
* value:指定对象的指定属性的执行函数
*/
const targetMap = new WeakMap<any, KeyToDepMap>()
export function effect<T = any>(fn: () => T) { export function effect<T = any>(fn: () => T) {
const _effect = new ReactiveEffect(fn) const _effect = new ReactiveEffect(fn)
_effect.run() _effect.run()
@@ -15,19 +25,38 @@ export class ReactiveEffect<T = any> {
/** /**
* 收集依赖 * 收集依赖
* @param target * @param target WeakMap的key
* @param key * @param key key代理对象的key, 当依赖被触发时,需要根据该key获取
*/ */
export function track(target: object, key: unknown) { export function track(target: object, key: unknown) {
console.log('收集依赖 track') if (!activeEffect) return
//尝试从 targetMap 中, 根据target获取map
let depsMap = targetMap.get(target)
//如果获取到的map不存在,则生成新的map对象, 并把该对象赋值给对应的value
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
//为指定map, 指定key, 设置回调函数
depsMap.set(key, activeEffect)
console.log(targetMap)
} }
/** /**
* 触发依赖 * 触发依赖
* @param target * @param target WeakMap的key
* @param key * @param key key代理对象的key, 当依赖被触发时,需要根据该key获取
* @param newValue
*/ */
export function trigger(target: object, key: unknown, newValue: unknown) { export function trigger(target: object, key: unknown, newValue: unknown) {
console.log('触发依赖 trigger') //依据target获取存储的map实例
const depsMap = targetMap.get(target)
if (!depsMap) {
return
}
//依据key, 从depsMap中取出value, 该value是一个ReactiveEffect类型的数据
const effect = depsMap.get(key) as ReactiveEffect
if (!effect) {
return
}
//执行effect中保存的fn函数
effect.fn()
} }

View File

@@ -16,5 +16,8 @@
effect(()=>{ effect(()=>{
document.querySelector('#app').innerText=obj.name document.querySelector('#app').innerText=obj.name
}) })
setTimeout(()=>{
obj.name='李四'
},2000)
</script> </script>
</html> </html>