Comprehensive parsing of $nextTick in Vue

  • 2021-10-15 09:50:37
  • OfStack

When the data is updated in the code, and you want to wait until the corresponding Dom is updated, then perform some logic. At this point, we will use $nextTick


funcion callback(){
 // Wait Dom Update, and then do something. 
}
$nextTick(callback) ; 

The official document explains nextTick as follows:

Perform a delayed callback after the next DOM update loop ends. Use this method immediately after modifying the data to get the updated DOM.

So, how does Vue do this, does it call our callback function after calling Api that modified Dom (appendChild, textContent = "xxxxx" and so on)?
What actually happened.

Source code

The implementation logic of nextTick is in this file:

vue/src/core/util/next-tick.js

The this we call. $nextTick is actually this method:


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
  })
 }
}

You can see

The callback function is stored in an array: callbacks. If no callback function is passed, this method returns 1 Promise, and then puts reslove as a callback function into flushCallbacks. So the documentation explains how to put callbacks, which is supposed to be a callback function, into then. Then, there is a variable called pending, and if it is not in pending, the function timerFunc is executed. And pending is equal to false by default. flushCallbacks This function executes all callback functions in one breath.

timerFunc

timerFunc is defined here

You can see that timerFunc executes flushCallbacks in an then of an Promise that has resolve.

Micro-task mechanism using js event loop

So, whenever we call $nextTick, if pending is false, timerFunc is called, and then timerFunc stuffs flushCallbacks at the end of the event loop, waiting to be called.


if (typeof Promise !== 'undefined' && isNative(Promise)) {
 const p = Promise.resolve()
 timerFunc = () => {
  p.then(flushCallbacks)
 }
}

flushCallbacks

Then there is a function in this file called flushCallbacks
Used to fully execute and empty the saved callback function.


function flushCallbacks () {
 pending = false
 const copies = callbacks.slice(0)
 callbacks.length = 0
 for (let i = 0; i < copies.length; i++) {
  copies[i]()
 }
}

pending

When does pending become true?

pending is true from the time timerFunc is called to the time flushCallbacks is called

That is, one event cycle

Callback functions added during pending are executed by flushCallbacks functions that are already waiting to be executed.

Core mechanism

After reading the source code, I found that there is no relationship between Dom update and one point except using the mechanism of one micro-task.

In fact, it is not only developers who call nextTick, but also nextTick when Vue updates Dom.

After the developer updates the bound data, Vue immediately calls nextTick, and stuffs the callback function of updating Dom into the event loop as a micro task.

Therefore, in the micro-task queue, the callback function of nextTick called by the developer is executed after the callback function of Dom.

But the problem comes again. According to the rendering mechanism of the browser, the rendering thread runs after the micro-task is executed. The rendering thread is not running, how can I get Dom?

Because the rendering thread only renders the Dom tree into UI, after Vue updates Dom, the new Dom node already exists in the Dom tree, and the js thread can already get the new Dom. The js thread will not be interrupted unless the developer reads the computed properties of the Dom and triggers the forced restream rendering thread.

Summarize

First, the timerFunc function is responsible for dropping callback functions to the end of the event loop Then, the nextTick function is responsible for saving all the callback functions. The timerFunc function is called when the nextTick function is called Updating Vue to Dom will also use nextTick, and before the developer calls nextTick. Because of the sequencing in 4 and the queuing nature of the event loop, it is ensured that the callback 1 of the developer's nextTick is set after the update of Dom

These are the details of parsing $nextTick in Vue. For more information about $nextTick in Vue, please pay attention to other related articles on this site!


Related articles: