Use of nextTick in Vue

In vUE development, we sometimes need to get information about the DOM element after it has been updated. When we assign a value to a variable, we need to get information about the DOM element before it has been updated, usually using the nextTick API. The official example is as follows

// Modify the data
vm.msg = 'Hello' 
// The DOM has not been updated yet

/ / recommend
Vue.nextTick(function () { 
    // The DOM is updated here
}) 

/ / do not recommend
Vue.nextTick().then(function () {
    // The DOM is updated here
})
Copy the code

The first option, recommended here, does not necessarily return a Promise on the nextTick principle, but may be implemented through MutationObserver, setImmediate, or setTimeout.

Vue.nexttick () does not have to be a microtask or macro task in the event loop. Promise and MutationObserver are microtasks, while setImmediate and setTimeout are macro tasks.

Principle analysis of nextTick in Vue

When we use nextTick() in Vue, we first define the Callbacks array (put the content that needs to be executed after the DOM element is updated into the Callbacks queue for execution after the DOM element is updated), the pending state (determine whether it is in the pending state to avoid multiple executions), and the pending state (determine whether it is in the pending state). The flushCallbacks() function (which executes everything stored in the callbacks once), the timerFunc() function (depending on browser support for Promises, MutationObserver, setImmediate, and setTimeout), The nextTick() function (which adds the callback content to the callbacks and calls timerFunc to execute the corresponding callback). The key source code is as follows:

  var callbacks = [];
  var pending = false;
  var timerFunc;
  
  function flushCallbacks () {
    pending = false;
    var copies = callbacks.slice(0);
    callbacks.length = 0;
    for (var i = 0; i < copies.length; i++) { copies[i](); }}if (typeof Promise! = ='undefined' && isNative(Promise)) {
    var p = Promise.resolve();
    timerFunc = function () {
      p.then(flushCallbacks);
      if (isIOS) { setTimeout(noop); }}; isUsingMicroTask =true;
  } else if(! isIE &&typeofMutationObserver ! = ='undefined' && (
    isNative(MutationObserver) ||
    MutationObserver.toString() === '[object MutationObserverConstructor]'
  )) {
    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 (typeofsetImmediate ! = ='undefined' && isNative(setImmediate)) {
    timerFunc = function () {
      setImmediate(flushCallbacks);
    };
  } else {
    timerFunc = function () {
      setTimeout(flushCallbacks, 0);
    };
  }
  
  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();
    }
    if(! cb &&typeof Promise! = ='undefined') {
      return new Promise(function (resolve) { _resolve = resolve; }}})Copy the code
Execution steps:
  • Call nextTick (CB, CTX) to add the corresponding callback to the callbacks
  • Determine whether pending is false and, if so, change it to true while calling the timerFunc() function (Promise, MutationObserver, setImmediate, setTimeout, etc.) To judge whether the browser supports this method in the code, the related functions such as isIOS, isIE and isNative have been encapsulated on the VUE principle.)
  • Return a Promise function when cb does not exist
  • FlushCallbacks () to execute the function added to the callbacks (at which point the DOM is updated)
Methods recommended:

It is recommended to do a demo, download the vue source code, log in to the Debugger in nextTick(), and step by step to see the source code running process.