# $nextTick
- 通过异步任务来优化一次同步任务中触发的多次
setter。 - 优先度
Promise.then()>new MutationObserver()>setImmediate()>setTimeout()
# queueWatcher
- 当数据发生改变时(触发setter),会通知相对应的
dep.subs[]里的所有Wathcer更新 - 当一个未设置
sync的Wathcer更新时 会将Wathcer添加到异步队列queueWathcer(this)中。 - 将当前同步任务中所有触发的 Wathcer 放在异步任务中运行
const queue = [] // 任务队列
export function queueWatcher (watcher: Watcher) {
const id = watcher.id
// 重复的 Watcher 不会入列
if (has[id] == null) {
// 缓存 map 判断 Watcher 是否已经在队列中
has[id] = true
if (!flushing) {
// 当前没有处于刷新队列状态, watcher直接进入队列
queue.push(wathcer)
} else {
/**
* 处于刷新队列状态的watcher根据id排序
* 用户自定义的wathcer后触发
* 保证父组件的watcher比子组件的先触发(父组件的wathcer的id会先于子组件的创建)
*/
let i = queque.length - 1
// id 从小到大 父组件的 watcher 优先触发
while (i > index && queue[i].id > watcher.id) {
i--
}
// id 放到比他当前 watcher 小的 后面
queue.splice(i + 1, 0, watcher)
}
if (!watting) {
waiting = true
if (process.env.NODE_ENV !== 'production' && !config.async) {
// 如果是同步的则直接调用刷新队列
flushSchedulerQueue();
return
}
nextTick(flushSchedulerQueue)
}
}
}
# nextTick
- 每次被调用都会判断当前
pending的状态,如果pending为false 则调用timerFunc在下一个任务队列执行callbacks[]
const callbacks = []
let pending = false
/**
* 1. 用户传入的 cb 使用 try catch 包装
* 2. flishSchedulerQueue 函数,将其放入 callbacks 数组
* 3. pending 保证同一时刻 只会有一个 fulshCallBacks 函数
*/
export function nextTick (cb?: Function, ctx?: Object) {
let _resolve
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
// handleError
}
} else {
_resolve(ctx)
}
})
if (!pending) {
pending = true
// 执行 timeFunc
timerFunc()
}
// 如果不传函数 返回的是一个 promise 返回的是第二个上下文参数
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}
# timerFunc
- 将任务放入异步任务队列中, 优先
Promise微任务
let timerFunc
if (typeof Promise !== 'undefined' && idNative(Promise)) {
const p = Promise.resolve()
timerFunc = () => {
p.then(fulshCallbacks)
// ios 特殊处理
if (isIos) setTimeout(noop)
}
// 使用微任务
isUsingMicroTask = true
} else if (
!isIE &&
typeof MutationObserver !== 'undefined' &&
isNative(MutationObserver) ||
MutationObserver.toString() === '[objdect, MutationObserverConstructor]'
) {
let counter = 1
const observer = new MutationObserver(flushCallbacks)
const textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter)
}
idUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
# flushCallbacks
- 将
pending置为 false 清空callbacks[]数组并执行数组中的每一个函数
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0)
callback.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
# flushSchedulerQueue
queueWatcher(this)都会被此方法处理
function flushSchedulerQueue () {
currentFlushTimestamp = getNow()
// 表示正在刷新队列 queueWatcher中
flushing = true
let watcher, id
/**
* 1. 保证更新顺序由父级到子级
* 2. 用户创建的 Wathcer 在其渲染 Wathcer 之前被执行,因为用户 Watcher 先于渲染 Watcher 创建
* 3. 如果一个组件再其父组件的 Wathcer 执行期间被销毁, 则它的 Watcher可以被跳过
*/
queue.sort((a, b) => a.id - b.id)
for (index = 0; index < queue.length; index++) {
wathcer = queue[index]
// 执行 before 钩子,在使用 watch 可通过配置项 before 传递
if (wathcer.before) {
watcher.before()
}
// 清除缓存的 Watcher
id = watcher.id
has[id] = null
watcher.run()
}
const activateQueue = activatedChildren.slice()
const updatedQueue = queue.slice()
// 重置has缓存对象
// waiting = flushing = false 表示队列结束
resetSchedulerState()
callActivatedHooks(activatedQueue)
callUpdatedHooks(updatedQueue)
}
function resetSchedulerState () {
index = queue.length = activatedChildren.length = 0
has = {}
waiting = flushing = false
}