const bucket = new WeakMap()
let activeEffect
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 = function (fn, options = {}) {
const effectFn = () => {
cleanup(effectFn)
activeEffect = effectFn
fn()
}
effectFn.deps = []
effectFn()
activeEffect.options = options
}
function trackFunc(target, key) {
if (!activeEffect) {
return
}
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)
}
function trigger(target, key) {
const depsMap = bucket.get(target)
if (!depsMap) {
return
}
let deps = depsMap.get(key)
if (deps) {
deps = new Set(deps)
deps.forEach(fn => {
if (fn.options.scheduler) {
fn.options.scheduler(fn)
} else {
fn()
}
})
}
}
function reactive(data) {
return new Proxy(data, {
get: (target, key) => {
const value = target[key]
trackFunc(target, key)
return value
},
set: (target, key, newValue) => {
target[key] = newValue
trigger(target, key)
}
})
}
const state = reactive({
num: 1
})
const jobQueue = new Set()
const p = Promise.resolve()
let isFlushing = false
const flushJob = () => {
if (isFlushing) {
return
}
isFlushing = true
p.then(() => {
jobQueue.forEach(job => job())
}).finally(() => {
isFlushing = false
})
}
effect(() => {
console.log('num-----', state.num)
}, {
scheduler(fn) {
jobQueue.add(fn)
flushJob()
}
})
let count = 100
while (count--) {
state.num++
}