refactor(reactivity): 重构响应式系统依赖收集机制
- 将依赖管理逻辑分离到独立的dep模块 - 创建Dep类型定义和createDep工厂函数 - 修改KeyToDepMap类型以使用Dep集合替代单个ReactiveEffect - 添加trackEffects函数用于统一跟踪依赖 - 实现triggerEffects函数用于批量触发依赖 - 增加triggerEffect函数用于触发单个依赖 - 在effect运行时添加注释说明首次getter触发 - 添加HTML示例文件验证多依赖收集功能
This commit is contained in:
7
packages/reactivity/src/dep.ts
Normal file
7
packages/reactivity/src/dep.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { ReactiveEffect } from './effect'
|
||||||
|
|
||||||
|
export type Dep = Set<ReactiveEffect>
|
||||||
|
export const createDep = (effects?: ReactiveEffect[]): Dep => {
|
||||||
|
const dep = new Set<ReactiveEffect>(effects) as Dep
|
||||||
|
return dep
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
type KeyToDepMap = Map<any, ReactiveEffect>
|
import { createDep, Dep } from './dep'
|
||||||
|
import { isArray } from '@vue/shared'
|
||||||
|
|
||||||
|
type KeyToDepMap = Map<any, Dep>
|
||||||
/**
|
/**
|
||||||
* 收集所有依赖的WeakMap实例
|
* 收集所有依赖的WeakMap实例
|
||||||
* key: 响应性对象
|
* key: 响应性对象
|
||||||
@@ -18,8 +21,9 @@ export let activeEffect: ReactiveEffect | undefined
|
|||||||
export class ReactiveEffect<T = any> {
|
export class ReactiveEffect<T = any> {
|
||||||
constructor(public fn: () => T) {}
|
constructor(public fn: () => T) {}
|
||||||
run() {
|
run() {
|
||||||
|
//当前被激活的effect实例
|
||||||
activeEffect = this
|
activeEffect = this
|
||||||
return this.fn()
|
return this.fn() //完成第一次getter行为的触发
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,9 +40,20 @@ export function track(target: object, key: unknown) {
|
|||||||
if (!depsMap) {
|
if (!depsMap) {
|
||||||
targetMap.set(target, (depsMap = new Map()))
|
targetMap.set(target, (depsMap = new Map()))
|
||||||
}
|
}
|
||||||
//为指定map, 指定key, 设置回调函数
|
|
||||||
depsMap.set(key, activeEffect)
|
let dep = depsMap.get(key)
|
||||||
console.log(targetMap)
|
if (!dep) {
|
||||||
|
depsMap.set(key, (dep = createDep()))
|
||||||
|
}
|
||||||
|
|
||||||
|
trackEffects(dep)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 利用dep依次跟踪指定key的所有effect
|
||||||
|
*/
|
||||||
|
export function trackEffects(dep: Dep) {
|
||||||
|
dep.add(activeEffect!)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,10 +68,29 @@ export function trigger(target: object, key: unknown, newValue: unknown) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
//依据key, 从depsMap中取出value, 该value是一个ReactiveEffect类型的数据
|
//依据key, 从depsMap中取出value, 该value是一个ReactiveEffect类型的数据
|
||||||
const effect = depsMap.get(key) as ReactiveEffect
|
const dep: Dep | undefined = depsMap.get(key)
|
||||||
if (!effect) {
|
if (!dep) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//执行effect中保存的fn函数
|
triggerEffects(dep)
|
||||||
effect.fn()
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 依次触发dep中保存的依赖
|
||||||
|
* @param dep
|
||||||
|
*/
|
||||||
|
export function triggerEffects(dep: Dep) {
|
||||||
|
const effects = isArray(dep) ? dep : [...dep]
|
||||||
|
//依次触发依赖
|
||||||
|
for (const effect of effects) {
|
||||||
|
triggerEffect(effect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发指定依赖
|
||||||
|
* @param effect
|
||||||
|
*/
|
||||||
|
export function triggerEffect(effect: ReactiveEffect) {
|
||||||
|
effect.run()
|
||||||
}
|
}
|
||||||
|
|||||||
29
packages/vue/examples/reactivity/reactive-dep.html
Normal file
29
packages/vue/examples/reactivity/reactive-dep.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Document</title>
|
||||||
|
<script src="../../dist/vue.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<p id="p1"></p>
|
||||||
|
<p id="p2"></p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
const { reactive,effect } = Vue
|
||||||
|
const obj=reactive({
|
||||||
|
name:'张三'
|
||||||
|
})
|
||||||
|
effect(()=>{
|
||||||
|
document.querySelector('#p1').innerText=obj.name
|
||||||
|
})
|
||||||
|
effect(()=>{
|
||||||
|
document.querySelector('#p2').innerText=obj.name
|
||||||
|
})
|
||||||
|
setTimeout(()=>{
|
||||||
|
obj.name='李四'
|
||||||
|
},2000)
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user