scheduler
by jin5354
HTML
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
Babel + JSX
// more detail go to
// https://github.com/jin5354/leaf-observable
let depUid = 1
let watcherUid = 1
const supportMO = typeof MutationObserver !== 'undefined'
function nextTick(task) {
return (() => {
/* istanbul ignore if */
if(supportMO) {
let counter = 1
const observer = new MutationObserver(task)
const textNode = document.createTextNode(String(counter))
observer.observe(textNode, {characterData: true})
textNode.textContent = 2
}else {
return Promise.resolve().then(task)
}
})()
}
const queue = []
const watcherIds = {}
let waiting = false
function flushSchedulerQueue() {
queue.forEach(watcher => {
watcher.run()
})
queue.length = 0
watcherIds = {}
waiting = false
}
function queueWatcher(watcher) {
const uid = watcher.uid
if(!watcherIds[uid]) {
watcherIds[uid] = true
queue.push(watcher)
if (!waiting) {
waiting = true
nextTick(flushSchedulerQueue)
}
}
}
class Dep {
constructor() {
this.id = depUid++ // 为每个 dep 标记一个 uid
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
depend() { // 依赖收集函数,在 getter 中执行,在 Dep.target 上找到当前 watcher,并添加依赖
Dep.target && Dep.target.addDep(this)
}
notify() {
this.subs.forEach(sub => {
sub.update()
})
}
}
Dep.target = null // Dep.target 用来暂存正在收集依赖的当前 watcher
// 现在 Wactcher 接收三个参数,第一个为依赖收集函数(如上文的 render),第二个为回调,第三个为附加配置
class Watcher {
constructor(expFn, cb, options = {}) {
this.uid = watcherUid++
this.context = options.context
this.immediate = options.immediate
this.expFn = expFn
this.depIds = new Set() //标记当前 watcher 已经加入到了哪些 dep
this.cb = cb
this.value = this.subAndGetValue()
this.clonedOldValue = _.cloneDeep(this.value)
}
/**
* [update 更新,根据 immediate 参数判断是否立刻执行回调]
*/
update() {
if(this.immediate) {
this.run()
}else {
queueWatcher(this)
}
}
/**
* [run 执行回调]
*/
run() {
let value =...