Vue nextTick执行时机分析
生活随笔
收集整理的這篇文章主要介紹了
Vue nextTick执行时机分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
先貼一段代碼,相信大家一定知道他的出處。沒錯,vue dev版 core/util/env.js中的一段代碼。
// Here we have async deferring wrappers using both microtasks and (macro) tasks. // In < 2.4 we used microtasks everywhere, but there are some scenarios where // microtasks have too high a priority and fire in between supposedly // sequential events (e.g. #4521, #6690) or even between bubbling of the same // event (#6566). However, using (macro) tasks everywhere also has subtle problems // when state is changed right before repaint (e.g. #6813, out-in transitions). // Here we use microtask by default, but expose a way to force (macro) task when // needed (e.g. in event handlers attached by v-on). let microTimerFunc let macroTimerFunc let useMacroTask = false// Determine (macro) task defer implementation. // Technically setImmediate should be the ideal choice, but it's only available // in IE. The only polyfill that consistently queues the callback after all DOM // events triggered in the same loop is by using MessageChannel. /* istanbul ignore if */ if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {macroTimerFunc = () => {setImmediate(flushCallbacks)} } else if (typeof MessageChannel !== 'undefined' && (isNative(MessageChannel) ||// PhantomJSMessageChannel.toString() === '[object MessageChannelConstructor]' )) {const channel = new MessageChannel()const port = channel.port2channel.port1.onmessage = flushCallbacksmacroTimerFunc = () => {port.postMessage(1)} } else {/* istanbul ignore next */macroTimerFunc = () => {setTimeout(flushCallbacks, 0)} }// Determine microtask defer implementation. /* istanbul ignore next, $flow-disable-line */ if (typeof Promise !== 'undefined' && isNative(Promise)) {const p = Promise.resolve()microTimerFunc = () => {p.then(flushCallbacks)// in problematic UIWebViews, Promise.then doesn't completely break, but// it can get stuck in a weird state where callbacks are pushed into the// microtask queue but the queue isn't being flushed, until the browser// needs to do some other work, e.g. handle a timer. Therefore we can// "force" the microtask queue to be flushed by adding an empty timer.if (isIOS) setTimeout(noop)} } else {// fallback to macromicroTimerFunc = macroTimerFunc }/*** Wrap a function so that if any code inside triggers state change,* the changes are queued using a (macro) task instead of a microtask.*/ export function withMacroTask (fn: Function): Function {return fn._withTask || (fn._withTask = function () {useMacroTask = trueconst res = fn.apply(null, arguments)useMacroTask = falsereturn res}) }export function nextTick (cb?: Function, ctx?: Object) {let _resolvecallbacks.push(() => {if (cb) {try {cb.call(ctx)} catch (e) {handleError(e, ctx, 'nextTick')}} else if (_resolve) {_resolve(ctx)}})if (!pending) {pending = trueif (useMacroTask) {macroTimerFunc()} else {microTimerFunc()}}// $flow-disable-lineif (!cb && typeof Promise !== 'undefined') {return new Promise(resolve => {_resolve = resolve})} } 復制代碼首先說明一下,2.5之前的版本不是這樣判斷的,但是為什么這個版本這么寫,注釋中已經說明了
所以制定了目前這個執行策略,即
優先執行micro任務,即promise里執行,如果有特殊需要,比如操作導致state變化時,那么則會選擇macro任務
setImmediate(IE10和edge支持)、MessageChannel、setTimeout都為宏任務 至于三個宏任務為什么這么排列請看對比
Promise、MutationObserver為微任務
總結
以上是生活随笔為你收集整理的Vue nextTick执行时机分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 让图片等比例缩放的三种方
- 下一篇: mysql主从复制的binlog和rel