Vue.nexttick () definition: A deferred callback is performed after the next DOM update loop

So, by definition, it is an asynchronous update queue, so let’s take a look at its source code

function renderMixin (Vue) { // install runtime convenience helpers installRenderHelpers(Vue.prototype); Vue.prototype.$nextTick = function (fn) { return nextTick(fn, this) }; Vue.prototype._render = function () { var vm = this; var ref = vm.$options; var render = ref.render; var _parentVnode = ref._parentVnode; if (_parentVnode) { vm.$scopedSlots = normalizeScopedSlots( _parentVnode.data.scopedSlots, vm.$slots, vm.$scopedSlots );  } // set parent vnode. this allows render functions to have access // to the data on the placeholder node. vm.$vnode = _parentVnode; // render self var vnode; try { // There's no need to maintain a stack becaues all render fns are called // separately from one another. Nested component's render fns are called // when parent component is patched. currentRenderingInstance = vm; vnode = render.call(vm._renderProxy, vm.$createElement); } catch (e) { handleError(e, vm, "render"); // return error render result, // or previous vnode to prevent render error causing blank component /* istanbul ignore else */ if (vm.$options.renderError) { try { vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e); } catch (e) { handleError(e, vm, "renderError"); vnode = vm._vnode; } } else { vnode = vm._vnode; } } finally { currentRenderingInstance = null; } // if the returned array contains only a single node, allow it if (Array.isArray(vnode) && vnode.length === 1) { vnode = vnode[0]; } // return empty vnode in case the render function errored out if (! (vnode instanceof VNode)) { if (Array.isArray(vnode)) { warn( 'Multiple root nodes returned from render function. Render  function ' + 'should return a single root node.', vm ); } vnode = createEmptyVNode(); } // set parent vnode.parent = _parentVnode; return vnode }; }Copy the code

Return nextTick(fn, this) ¶ Return nextTick(fn, this) ¶ Return nextTick(fn, this) ¶ return nextTick(fn, this) ¶

Now let’s look at the nextTick function

function nextTick (cb, ctx) { var _resolve; callbacks.push(function () { 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(function (resolve) { _resolve = resolve; }) } } if (typeof Promise ! == 'undefined' && isNative(Promise)) { var p = Promise.resolve(); timerFunc = function () { 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); }}; isUsingMicroTask = true; } else if (! isIE && typeof MutationObserver ! == 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]' )) { // Use MutationObserver where native Promise is not available, // e.g. PhantomJS, // (#6466 MutationObserver is unreliable in IE11) var counter = 1; var observer = new MutationObserver(flushCallbacks); var textNode = document.createTextNode(String(counter)); observer.observe(textNode, { characterData: true }); timerFunc = function () { counter = (counter + 1) % 2; textNode.data = String(counter); }; isUsingMicroTask = true; } else if (typeof setImmediate ! == 'undefined' && isNative(setImmediate)) { // Fallback to setImmediate. // Techinically it leverages the (macro) task queue, // but it is still a better choice than setTimeout. timerFunc = function () { setImmediate(flushCallbacks); }; } else { // Fallback to setTimeout. timerFunc = function () { setTimeout(flushCallbacks, 0); }; }Copy the code

There are a couple of judgments here,

1. When Promise is supported, the function call is delayed by promise. then. Promise delays the function to the end of the current function call stack through pending judgment, that is, the function/is called at the end of the function call stack

**MutationObserver **MutationObserver is a new feature of H5. It listens for CHANGES to the DOM node and executes a callback function after all changes to the DOM are complete.

Specifically, there are several changes to the monitoring:

ChildList: Changes to child elements

Attributes: Changes to attributes

CharacterData: Changes in node content or node text

Subtree: Changes to all subordinate nodes (including children and children of children)

3, timerFunc function so obviously, when it is determined that the browser does not support the above two week method, setTimeout will be used to delay the update

conclusion

When calling the $nextTick function, Vue first uses native Promise.then and MutationObserver in preference to the current browser environment, and if neither is supported, setTimeout is used instead to delay the function’s use until the DOM is updated

As mentioned in the first section, knot and macro tasks, $nextTick encounter promise conditions, microtask execution mentioned. If you are interested in the key, see the corresponding macro task and micro task introduction _juejin.cn/post/684490… _

Promise, rounding _juejin. Cn/post / 685457… _

What happens when you manipulate a primitive array in a WEBGL JS loop? React ShoudComponentUpdate React ShoudComponentUpdate Stop rendering vue why don’t you use 11 methods for deep copy shallow copy Vue vue $nextTick Deep parsing Deep Revealing Promise microtask registration and execution Process How does the V8 engine execute a section of JS code? Http3.0 2.0 1.0 compare macro tasks and micro tasks in detail