微任务>DOM渲染>宏任务
$nextTick是微任务,微任务的执行是在DOM渲染前的;
经过验证$nextTick是在DOM渲染后触发的;
互相矛盾,可以解释一下吗?
来自chatGpt
在 Vue.js 2.x 版本中,$nextTick 的实现确实是将回调函数放入微任务队列中,并且在DOM渲染前执行。但在 Vue.js 3.x 中,由于采用了新的响应式系统和渲染机制,$nextTick 的实现方式已经改变。现在,$nextTick 实际上将回调函数排入下一个渲染周期的更新队列中,在当前更新周期同步任务执行完成之后,执行下一个更新周期的渲染工作,进而触发 $nextTick 回调函数的执行。
因此,在 Vue.js 3.x 中,$nextTick 的执行时间点已不再受到 DOM 渲染的影响,而是与当前更新周期的渲染工作有关。
上文说到了,我们使用ref获取DOM节点时,因为节点可能还没渲染好,所以我们无法正常获取到,那么vue内部的$nextTick是怎么做到在DOM节点渲染好后才去获取的呢
我们先稍微看一下源码
export const nextTick = (function () {
const callbacks = []
let pending = false
let timerFunc
function nextTickHandler () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
if (typeof Promise !== 'undefined' && isNative(Promise)) { // 使用promise
var p = Promise.resolve()
var logError = err => { console.error(err) }
timerFunc = () => {
p.then(nextTickHandler).catch(logError)
if (isIOS) setTimeout(noop)
}
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
isNative(MutationObserver) ||
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) { // 使用MutationObserver
var counter = 1
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter)
}
} else { // 使用setTimeout
timerFunc = () => {
setTimeout(nextTickHandler, 0)
}
}
return function queueNextTick (cb?: Function, ctx?: Object) {
let _resolve
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
if (!pending) {
pending = true
timerFunc()
}
if (!cb && typeof Promise !== 'undefined') {
return new Promise((resolve, reject) => {
_resolve = resolve
})
}
}
})()