# 第 4 章 响应系统的作用和实现
# 1. 响应式数据与副作用函数
示例:
const obj = { text: 'hello world' };
// 副作用函数
function effect() {
document.body.innerText = obj.text;
}
obj.text = 'hello 张三';
当 obj.text
的值变化后,如果 effect()
能自动重新执行,则 obj
就是响应式数据
# 2. 响应式数据的基本实现
说明:
- 读取属性时,将副作用函数存储到桶中
- 设置属性时,将副作用函数从桶中取出来执行
微型响应系统:
const bucket = new Set();
const data = { text: 'hello world' };
const obj = new Proxy(data, {
get(target, key) {
bucket.add(effect);
return target[key];
},
set(target, key, newValue) {
target[key] = newValue;
bucket.forEach((fn) => fn());
return true;
}
});
测试:
function effect() {
document.body.innerText = obj.text;
}
effect();
setTimeout(() => {
obj.text = 'hello 张三';
}, 2000);
# 3. 设计一个完善的响应式系统
原理:
桶的结构:
target1
prop1
effectFn1
effectFn2
prop2
effectFn1
target2
prop1
effectFn1
桶的实现:
bucket(WeekMap)
key: target
val: depsMap(Map)
depsMap(Map)
key: prop
val: effectFns(Set)
effectFns(set)
val: effectFn
代码:
let activeEffect;
function effect(fn) {
activeEffect = fn;
fn();
}
const data = {
name: '张三',
age: 18
};
const bucket = new WeakMap();
const obj = new Proxy(data, {
get(target, key) {
track(target, key);
return target[key];
},
set(target, key, newVal) {
target[key] = newVal;
trigger(target, key);
}
});
function track(target, key) {
if (!activeEffect) {
return target[key];
}
let depsMap = bucket.get(target);
if (!depsMap) {
depsMap = new Map();
bucket.set(target, depsMap);
}
let deps = depsMap.get(key);
if (!deps) {
deps = new Set();
depsMap.set(key, deps);
}
deps.add(activeEffect);
activeEffect = null;
}
function trigger(target, key) {
const depsMap = bucket.get(target);
if (!depsMap) {
return;
}
const effects = depsMap.get(key);
if (!effects) {
return;
}
effects.forEach((fn) => fn());
}
测试:
document.body.innerHTML = `
<div id="box1"></div>
<div id="box2"></div>
`;
effect(function() {
console.log('读取 obj.name');
document.getElementById('box1').innerText = obj.name;
});
effect(function() {
console.log('读取 obj.age');
document.getElementById('box2').innerText = obj.age;
});
setTimeout(() => {
obj.name = '李四';
}, 2000);
setTimeout(() => {
obj.age = 19;
}, 4000);
# 4. 分支切换与 cleanup
上一篇: 下一篇:
本章目录