代码逻辑梳理:
-
callbacks 数组用于存储待执行的回调函数,waiting 变量用于标记是否有待执行的回调函数。
-
flushCallbacks 函数用于执行所有存储在 callbacks 数组中的回调函数,并在执行完成后将 waiting 设置为 false。
-
timer 函数根据环境选择合适的定时器来执行回调函数。优先选择 Promise 的微任务执行,如果不支持则尝试使用 MutationObserver,其次是 setImmediate,最后是默认的 setTimeout。
-
nextTick 函数用于将回调函数加入待执行队列,并触发执行。如果当前没有待执行的回调函数,则调用 timer 函数来触发执行,并标记有待执行的回调函数。
整体流程是将回调函数加入队列,通过选择合适的定时器来异步执行这些回调函数,保证它们在下一个微任务或宏任务中被执行
javascript
let callbacks = [] // 存储待执行的回调函数
let waiting = false // 标记是否有待执行的回调函数
// 执行所有待执行的回调函数
function flushCallbacks() {
callbacks.forEach((cb) => cb()) // 依次执行回调函数
waiting = false // 标记执行完成
}
// 根据环境选择合适的定时器执行回调函数
function timer(flushCallbacks) {
let timerFn = () => {} // 默认空函数
// 使用 Promise
if (typeof Promise !== 'undefined') {
timerFn = () => {
Promise.resolve().then(flushCallbacks) // 在微任务中执行回调函数
}
} else if (typeof MutationObserver !== 'undefined') { // 使用 MutationObserver
let textNode = document.createTextNode(1)
let observe = new MutationObserver(flushCallbacks)
observe.observe(textNode, {
characterData: true
})
timerFn = () => {
textNode.textContent = 3
}
} else if (typeof setImmediate !== 'undefined') { // 使用 setImmediate
timerFn = () => {
setImmediate(flushCallbacks)
}
} else { // 默认使用 setTimeout
timerFn = () => {
setTimeout(flushCallbacks, 0)
}
}
timerFn()
}
// 将回调函数加入待执行队列,并触发执行
function nextTick(cb) {
callbacks.push(cb) // 将回调函数加入队列
if (!waiting) {
timer(flushCallbacks) // 触发执行回调函数
waiting = true // 标记有待执行的回调函数
}
}