解析src\core\util\next-tick.js
export function nextTick (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()
}
// $flow-disable-line
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}
内容:
- 接收形参(回调函数,ctx上下文)
- callbacks异步队列添加回调函数,指向当前上下文,如果没有则添加为_resolve,后面通过Promise进行调用
- 当前值如果为等待状态,调用回调函数
timerFunc() - 如果没有提供回调且在支持 Promise 的环境中,则返回一个 Promise
在刚进入当前js,提前给timerFunc()做个判断走哪个时机,逻辑依次从微任务到宏任务的降级执行
if (typeof Promise !== 'undefined' && isNative(Promise)) {
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
if (isIOS) setTimeout(noop)
}
isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
isNative(MutationObserver) ||
MutationObserver.toString() === '[object 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)
}
isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
内容:Promise > MutationObserver > setImmediate > setTimeout
原理:vue利用异步队列的方式调用nextTick回调函数的先后顺序,因为浏览器兼容性问题和微任务优选宏任务的机制,进行降级处理