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!