响应系统的实现
作用
1. 数据变化监听
2. 属性分支切换
3. 解决副作用嵌套出现混乱
4. 调度问题,将执行权交给用户
const data = {text: 'hello world', ok: true, foo: 1};
const bucket = new WeakMap();
let activeEffect;
let effectStack = [];
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) {
bucket.set(target, (depsMap = new Map()))
}
let deps = depsMap.get(key);
if(!deps) {
depsMap.set(key, (deps = new Set()));
}
deps.add(activeEffect);
activeEffect.deps.push(deps);
}
function trigger(target, key) {
const depsMap = bucket.get(target);
if(!depsMap)return;
const effects = depsMap.get(key);
const effectsSet = new Set();
effects&& effects.forEach(fn => {
if(activeEffect !== fn) {
effectsSet.add(fn);
}
})
effectsSet.forEach(fn => {
fn.options.scheduler ? fn.options.scheduler(fn) : fn(); //解决调度问题
});
}
function cleanup(effectFn) {
for(let i=0; i< effectFn.deps.length; i++) {
const deps = effectFn.deps[i];
deps.delete(effectFn);
}
effectFn.deps.length = 0;
}
const effect = (fn, options={})=>{
const effectFn = () =>{
cleanup(effectFn);
activeEffect = effectFn;
effectStack.push(effectFn);//解决嵌套问题
fn();
effectStack.pop();//解决嵌套问题
activeEffect = effectStack[effectStack.length -1]; //解决嵌套问题
}
effectFn.options = options;
effectFn.deps = [];
effectFn();
}
let isFlushing = false;
let p = Promise.resolve();
const jobQueue = new Set();
function flushJob() {
if(isFlushing) return;
isFlushing = true;
p.then(() => {
jobQueue.forEach(fn => fn())
}).finally(()=>{
isFlushing = true;
})
}
effect(() =>{
console.log(obj.foo);
}, {
scheduler(fn){
jobQueue.add(fn);
flushJob();
}
})
obj.foo++;
obj.foo++;