Analysis of Vue's nextTick principle

Assuming that the current template code is <div id="a">{{a}}</div>, then we write the following code in the mounted hook:

this.a = '纳尼?!';
this.$nextTick(function(){
    console.log($('#a')[0].textContent);
})

So the internal execution flow of vue is shown in the following figure:

write picture description here

First of all, the external code (that is, the code in the mounted hook) is a whole task task, and the microtask task queue will be executed after it is executed.
Analysis of the first line of code: this.a = '纳尼?!';
The previous article mentioned that the data binding of vue is achieved by modifying the get/setter, so this.a = '纳尼?!';when it is executed, the setter of the a property will be triggered, thereby notifying all watchers subscribed to the a property. After the watcher receives the notification, if the watcher does not exist in the update array, it will be pushed into the update array (guarantee that a single task will only modify the dom once). Then put flushBatcherQueue into the cb array of nextTick (the role of flushBatcherQueue is to traverse the watcher update array and execute the update method of the watchers). Then modify the textNode monitored by MO, which will trigger MO to add its callback function to the microtask queue.
Analyze the second line of code: this.$nextTick(function(){ console.log($('#a')[0].textContent); })
This code will add the console function to the cb array of nextTick, and then the task execution is completed, and the microtask queue will be executed. At this time, the callback function of MO will be executed, and the callback function of MO will execute the cb array of nextTick, that is, first traverse and execute the watcher, and then execute the console callback we defined.
To sum up: in a task code, data may be modified multiple times. And we can't immediately notify the watcher to update the dom every time it is modified. The alternative is to add the watcher to the update array. After the task code is executed (that is, all synchronization codes are executed), it means that this round of data modification has ended. At this time, we can trigger the update operation of the watcher, so no matter how many times the task code is modified before, we will only update the DOM once in the end.

PS: The point of nextTick is to put the traversal of the watcher in the flushBatcherQueue step into the microtask. It doesn't matter whether you use MO or Promise.then. Environments where neither is well compatible will be forced to use setTimeout instead. But setTimeout puts the callback function in the macrotask queue, and the browser will trigger ui rendering when the microtask queue is cleaned up, so setTimeout will waste its previous browser ui rendering opportunity. (That is, at least two ui renderings are required to render the updated DOM)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324736539&siteId=291194637