文章目录
1. 入口
src\core\instance\index.js
里面的renderMixin(Vue)
src\core\instance\render.js
里面的
export function renderMixin (Vue: Class<Component>) { installRenderHelpers(Vue.prototype) Vue.prototype.$nextTick = function (fn: Function) { return nextTick(fn, this) } ... }
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 }) } }
2. nextTick
执行过程
- 确定使用微任务还是宏任务,并确定
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) } }
- 当
nextTick
被调用且回调函数处于非pending
时,调用TimerFuc
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 }) } }
- func是一个微任务或者宏任务的函数,里面放着
flushCallbacks
清空当前回调队列的任务
function flushCallbacks () { pending = false // arrayObject.slice(start,end) 返回选定元素 const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } }
注意:flushCallbacks
里面的copies
是调用2的nextTick
push进去的,也就是我们定义的回调函数
if (cb) { try { cb.call(ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) }
回顾一下我们使用Vue的时候怎么使用nextTick就清楚了
this.$nextTick(()=>{ console.log('hahha') })
()=>{ console.log('hahha') } // 这个函数就是我们的copies啦
贴个官方的图吧
- 到这里
nextTick
的原理就很清楚啦。