源码:
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)) { 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]' )) { 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 { 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 }) } } })()nextTick用于延迟执行一段代码,它接收2个参数:回调函数和执行回调函数的上下文环境(也就是ctx,全名Execution Context),如果没有提供回调函数,那么将返回promise对象。
至于为何需要延时执行一段代码,vue官方也给过解释: Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。
首先它定义了三个变量, callbacks:存储需要执行的回调函数; pending:标记是否正在执行回调函数; timerFunc:触发执行回调函数;
下面是nextTickHandler函数,用来给timerFunc赋值 并执行callbacks中存储的所有回调函数。
接下来上了个大判断,vue会按照最优方案去触发回调: 1,是否支持promise,如果是,则使用promise来执行回调函数; 2,是否支持MutationObserver,如果是,则使用MutationObserver来执行回调函数,这是H5新增的一个API,用来监视DOM变动; 3,如果前两者都不支持,那就用最后的老伙计,setTimeout来执行,并设置延时为0。
最后返回一个queueNextTick函数 ,这里接收的即是用户输入的回调函数和执行上下文,并且将回调函数存入callbacks中。(queue是队列的意思)
所以其实整个nextTick函数先执行的是queueNextTick,然后用timerFunc进行延时,最后用nextTickHandler执行函数。
