Abstract
This article explains how $nexTick works, what’s behind this. Data item = new value, and how nextTick relates to promise. Reading this article requires an understanding of vUE’s basic processes, microtasks, and promises.
content
- Seven test questions
- How $nextTick works, how it relates to Promise
This. data item = new value
What did he do behind his back- Answer and explanation of 7 test questions
test
Here is the basic code
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, Initial - scale = 1.0 "> < title > Document < / title > < / head > < body > < div id =" app "> < div id =" div "> {{a}} < / div > < button @ click = "BTN" > BTN < / button > < / div > < script SRC = "https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.js" > < / script > < script > var vm = new Vue({ el:"#app", data:{ a :1 }, methods: { btn() { this.a = 2 const div = document.getElementById('div') this.$nextTick(() => { console.log('nextTick', div.innerHTML) }) console.log(div.innerHTML) } } }) </script> </body> </html>Copy the code
The question is: what is the order and result of the output after the button is clicked? The answer is: 1. nextTick 2; I don’t think that’s hard for you.
Ok, there are seven similar problems below, and I’ve only given the parts of BTN () to save code.
Title 1
Topic 2
Topic 3
Topic 4
Topic 5
Topic 6
Topic 7
If you can answer it clearly, please go straight to the bottom, leave a message to me, let me worship. If you have any regrets, or if you don’t know how to do it, please stick to it
What does this.$nextTick do
Reading the source code is the best way to do this, and nextTick’s source code is as follows (with cuts) :
function nextTick (cb, ctx) {
var _resolve;
callbacks.push(function () {
// Add the callback to the callbacks array
cb.call(ctx);
});
// After ensuring that the current microtask is completed,
// Push the callbacks to the next microtask
if(! pending) { pending =true;
timerFunc(); / / call timerFunc}}var timerFunc;
if (typeof Promise! = ='undefined' && isNative(Promise)) {
var p = Promise.resolve();
timerFunc = function () {
p.then(flushCallbacks);
};
isUsingMicroTask = true;
} else if(! isIE &&typeofMutationObserver ! = ='undefined' && (
isNative(MutationObserver) ||
// PhantomJS and iOS 7.x
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
// Use MutationObserver where native Promise is not available,
PhantomJS, iOS7, Android 4.4
// (#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 (typeofsetImmediate ! = ='undefined' && isNative(setImmediate)) {
timerFunc = function () {
setImmediate(flushCallbacks);
};
} else {
timerFunc = function () {
setTimeout(flushCallbacks, 0);
};
}
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
Copy the code
Keep an eye on two things: Callbacks and timerFunc.
Callbacks are an array that will be used to collect callbacks.
TimerFunc is an asynchronous function that is dynamically determined. The priorities are as follows: promise. then > MutationObserver > setImmediate > setTimeout. In standard browsers (the promise enabled environment), we can think of it as promise.then. So you can use the following diagram to illustrate nextTick’s capabilities.
It does two things:
- Push the callback function into its internally maintained Callbacks array
- Register microtasks with promise.resolve ().then to perform all callbacks in callbacks.
This is Figure 1. There will be another figure 2 in the next section. Once you know two pictures, you have no problem with the first seven questions.
What does this.a=2 do
Suppose the original data was a=1. Now what does this.a=2 do?
And I have a map for you
There are many intermediate processes in the figure above. To simplify the process, see the following illustration:
This is Figure 2. To sum up:
- The data change causes nextTick execution, which adds watcher.run to the callbacks, an internally maintained array, and then to the microtask sequence.
- NextTick is the key to asynchronous updates.
There was a figure 1 in the explanation above, and now there is a figure 2. Now that you have two pictures, you can go straight to the answer and explanation section of the practice questions.
If you want to further impress, you can look at the following process:
After modifying the data, activate the setter for the property,
Call dep notify to notify the subscriber vue2 source directory/SRC/core/observer/dep. Js
Each subs[I] is a Watcher (one watcher per component), and its update method is as follows
Vue2 source directory/SRC/core/observer/watcher. Js
Note that the update is not executed immediately, but instead enters the queueWatcher function, which is defined in scheduler.js and is used for uniform queue management of watcher.
Vue2 source directory/SRC/core/observer/scheduler, js, it defines a flushSchedulerQueue function, in this function to call the watch, but it is not directly, but rather to the nextTick. This is where asynchrony begins. Note line 165,166 in the following code: Remove the duplicate watcher based on the WATcher ID.
Most importantly, let’s go to nextTick on line 187.
FlushSchedulerQueue = flushSchedulerQueue = flushSchedulerQueue
function flushSchedulerQueue () {
queue.sort((a, b) = > a.id - b.id)
// The watcher id is ordered. The parent component is created before the child component, so its Watcher ID must be smaller
// will be executed first
for (index = 0; index < queue.length; index++) {
watcher = queue[index]
watcher.run()// Includes new virtual DOM generation, diff algorithm, updated view, etc}}Copy the code
NextTick was analyzed earlier.
FlushCallbacks =>callbacks=>flushSchedulerQueue =>watcher.run in a microtask.
You can go back to Figure 2 again.
Test answers and explanations
Title 1
Answer: 1; nextTick 2;
Analysis process:
Line 3: this.a=3 modifys the data to add watcher.run to the callbacks, call callbacks=[watcher.run], and push to the microtask queue: […callbacks]
QueueWatcher () has the watcher function removed, so render will not queue up again.
Line 5: this.$nextTick adds the callback to the end of the microtask queue. The microtask queue has: [watcher.run, callback on line 5]
Line 8: Prints 1, at which point the synchronization task ends.
Start fetching task execution sequentially from the microtask queue.
Watcher. Run: updates the view, and when it’s done, the content of the div in the view is 2
Callback in line 5: Prints nextTick 2
Topic 2
Answer: 1; nextTick 1;
Analysis process:
Line 3: this.$nextTick adds the callback to the callbacks, callbacks=[callback on line 5]. Microtask queue has: [… callbacks]
Line 6: this. A =2 modifys the data to add watcher.run to the callbacks, callbacks=[callback on line 5, watcher.run]
Line 7: Prints 1, at which point the synchronization task ends.
Start fetching task execution sequentially from the microtask queue.
Callback in line 5: Prints nextTick 1. Notice that it is executed before watcher.run. So the view is not updated.
Watcher. Run: updates the view, and when it’s done, the content of the div in the view is 2.
Topic 3
Answer: 1. nextTick 2;
Topic 4
Answer: 1. nextTick 2; resolve 2;
Analysis process:
Line 1: this.a=2 modifies the data by adding the watcher.run function to the callbacks, callbacks=[watcher.run], and the callback to the microtask queue. Microtask queue has: […callbacks]
Line 4: Register a microtask. Microtask queue has: […callbacks, console.log(‘resovle’)]
Line 7: this.$nextTick adds the callback to the end of the callbacks. Callbacks =[watcher. Run, nextTick callback], microtask queue: […callbacks, console.log(‘resovle’)]
Line 10: Prints 1, at which point the synchronization task ends.
Start fetching task execution sequentially from the microtask queue. So the answer is:
Watcher.run -> nextTick callback –>console.log(‘resovle’)
Topic 5
Answer: 1. resolve 1; nextTick 1;
Topic 6
Answer: 1; nextTick 1; resolve 2;
Topic 7
Answer: 1. nextTick 2; resolve 2
summary
$nextTick is an asynchronous function that in standard browsers (which support native Promises) uses promise.resolve ().then() to implement asynchronous functionality.
$nextTick does two things: it collects callbacks into internal closure maintenance callbacks, and it collects callbacks into internal closure maintenance callbacks. In the microtasks in this event loop, the callbacks in callbacks are executed in turn.
When the data changes, $nextTick is still called, and the incoming callback is water.run after being reordered.
Reprinted from mp.weixin.qq.com/s/Gaa7tDLR-…