Simple understanding of nextTick in vue

Simple understanding of nextTick in vue

Official website explanation

Maybe you haven't noticed yet, Vue performs DOM updates asynchronously. As long as data changes are observed, Vue will open a queue and buffer all data changes that occur in the same event loop. If the same watcher is triggered multiple times, it will only be pushed to the queue once. This removal of duplicate data during buffering is very important to avoid unnecessary calculations and DOM operations. Then, in the next event loop "tick", Vue refreshes the queue and executes the actual (deduplicated) work. Vue internally tries to use native Promise.then and MessageChannel for asynchronous queues. If the execution environment does not support it, setTimeout(fn, 0) will be used instead.

For example, when you set vm.someData ='new value', the component will not be re-rendered immediately. When the queue is refreshed, the component will be updated at the next "tick" when the event loop queue is emptied. In most cases, we don't need to care about this process, but if you want to do something after the DOM state is updated, it may be a bit tricky. Although Vue.js usually encourages developers to think in a "data-driven" way and avoid direct contact with the DOM, sometimes we do. In order to wait for Vue to finish updating the DOM after the data changes, you can use Vue.nextTick(callback) immediately after the data changes. In this way, the callback function will be called after the DOM update is complete.

If the same watcher is triggered multiple times, it will only be pushed into the queue once. What does this mean? Just give an example.

   <div id="example">
        {
    
    {
    
     msg }}
   </div>

<script type="text/javascript">
var vm = new Vue({
    
    
    el: '#example',
    data: {
    
    
        msg: 1
    },
    created(){
    
    
        this.msg = 1
        this.msg = 2
        this.msg = 3
    },
    watch: {
    
    
        msg(){
    
    
            console.log(this.msg)
        }
    }
})
</script>

What will the browser console output? The answer is 3, not 1, 2, 3. This is what the official website says is multiple triggers and will only be pushed into the queue once.
Look at another example

  <div id="example">
        {
    
    {
    
     msg }}
    </div>

var vm = new Vue({
    
    
    el: '#example',
    data: {
    
    
        msg: '123'
    }
})
vm.msg = 'new message'
console.log(1)
console.log(vm.$el.innerText)
console.log(2)
Vue.nextTick(()=>{
    
    
    console.log(vm.$el.innerText)
})
console.log(3)
</script>

The output in the Google Chrome console is

1
123
2
3
new message

Is it different from what I imagined? Why is the last typed'new message' instead of the last 3 of the code? Why the first print of vm.$el.innerText is 123 instead of the'new message' after the assignment To understand JavaScript's EventLoop, this will be discussed later, let's look at an example, this example is also a simplified version of why I can't get the div instance before

  <div id="example">
        <div v-for="i in number" :ref="'div'+i" v-if="number > 0">{
    
    {
    
    i}}</div>
        <button @click="addNumber">点击</button>
    </div>

<script type="text/javascript">
var vm = new Vue({
    
    
    el: '#example',
    data: {
    
    
        number: 0
    },
    methods:{
    
    
        addNumber(){
    
    
            this.number = 3
            console.log(1)
            console.log(this.$refs['div1'])
            console.log(2)
            this.$nextTick(()=>{
    
    
                console.log(this.$refs['div1'])
            })
            console.log(3)
        }
    }
})
</script>

The print result is

1
undefined
2
3
[div]

You can see that the div element with id div1 is not retrieved for the first time, but it is retrieved in nextTick. This corresponds to the official website. In order to wait for Vue to finish updating the DOM after the data changes, you can use Vue.nextTick(callback) immediately after the data changes.

Javascript EventLoop (event loop)

So many strange behaviors above are actually related to JavaScript's EventLoop. Below I will try to explain this EventLoop.
There is a well-known video explaining this, Philip Roberts's speech "Help, I'm stuck in an event-loop", although it is in pure English, it can still be understood with the animation on the PPT. Let me copy and paste the explanation of Teacher Ruan Yifeng, because it is really very good.

Why is JavaScript single-threaded?

A major feature of the JavaScript language is single thread, that is, only one thing can be done at the same time. So, why can't JavaScript have multiple threads? This can improve efficiency.

The single thread of JavaScript is related to its purpose. As a browser scripting language, the main purpose of JavaScript is to interact with users and manipulate the DOM. This determines that it can only be single-threaded, otherwise it will bring complex synchronization problems. For example, suppose that JavaScript has two threads at the same time. One thread adds content to a certain DOM node, and the other thread deletes this node. At this time, which thread should the browser use?

Therefore, in order to avoid complexity, JavaScript has been single-threaded since its birth. This has become a core feature of the language and will not change in the future.

In order to utilize the computing power of multi-core CPUs, HTML5 proposes the Web Worker standard, which allows JavaScript scripts to create multiple threads, but the child threads are completely controlled by the main thread and must not operate the DOM. Therefore, this new standard does not change the nature of JavaScript single-threaded.

Task queue

Single thread means that all tasks need to be queued, and the previous task ends before the next task is executed. If the previous task takes a long time, the next task has to wait forever.

If the queue is due to a large amount of calculations and the CPU is too busy, that’s fine, but in many cases the CPU is idle because the IO devices (input and output devices) are very slow (for example, Ajax operations read data from the network) and have to Wait for the results to come out, and then proceed.

The designers of the JavaScript language realized that at this time, the main thread can completely ignore the IO device, suspend the waiting tasks, and run the tasks that are ranked later. Wait until the IO device returns the result, then go back and continue the execution of the suspended task.

Therefore, all tasks can be divided into two types, one is synchronous tasks (synchronous), and the other is asynchronous tasks (asynchronous). Synchronous tasks refer to tasks queued for execution on the main thread. Only the previous task can be executed before the next task can be executed; asynchronous tasks refer to tasks that do not enter the main thread but enter the "task queue" For tasks, only when the "task queue" informs the main thread that an asynchronous task can be executed, the task will enter the main thread for execution.
Specifically, the operating mechanism of asynchronous execution is as follows. (The same is true for synchronous execution, because it can be viewed as asynchronous execution without asynchronous tasks.)

(1) All synchronization tasks are executed on the main thread, forming an execution context stack.
(2) In addition to the main thread, there is also a "task queue". As long as the asynchronous task has a running result, an event is placed in the "task queue".
(3) Once all synchronization tasks in the "execution stack" are executed, the system will read the "task queue" to see what events are in it. Those corresponding asynchronous tasks end the waiting state, enter the execution stack, and start execution.
(4) The main thread keeps repeating the third step above.
Insert picture description here

The main thread reads events from the "task queue". This process is cyclical, so the entire operation mechanism is also called Event Loop.
Insert picture description here

When the main thread is running, a stack is generated. The stack is to store variables. The stack records the order of execution. If it encounters callback functions, DOM operations such as clicking, mouse up, etc., the setTimeout operation will be placed in the task queue, only the code in the stack The code will be taken from the task queue and executed after execution. So this is why in the above code example, although console.log(3) is at the end of the code, it is output before the code in nextTick. You can understand that a bunch of code, the method that should be placed in the stack, is placed in the stack, and then the asynchronous operations in this bunch of code are placed in the task queue, and then the code in the stack is executed, and the code in the stack is executed. The code in the task queue is executed, so the order of execution and writing of the code is not always the same.

Task queue

The above task queue is divided into two types, the execution order is also a little different, Macrotasks and Microtasks

  • Macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering
  • Microtasks: process.nextTick, Promises, Object.observe (obsolete), MutationObserver
    What is the difference between Macrotasks and Microtasks? Let's take setTimeout and Promises as examples.
  console.log('1');
    setTimeout(function() {
    
    
      console.log('2');
    }, 0);
    Promise.resolve().then(function() {
    
    
      console.log('3');
    }).then(function() {
    
    
      console.log('4');
    });
    console.log('5');
    //输出结果:
    1
    5
    3
    4
    2

The reason is that the function of the then method in Promise will be pushed into the microtasks queue, and the task of setTimeout will be pushed into the macrotasks queue. In each event loop, macrotask will only fetch one execution, while microtask will keep fetching until the microtasks queue is emptied. conclusion as below:

  1. Microtask will prioritize macrotask execution
  2. Microtasks will be cyclically extracted to the execution stack of the main thread of the execution engine. Macrotask will not be executed until the microtasks task queue is emptied.
    [Note: In general, macrotask queues will be directly called task queues, and only microtask queues will be specifically specified.

Author: sea stars __xcdh
reprint Source: simple to understand vue in nextTick

Guess you like

Origin blog.csdn.net/weixin_47160442/article/details/112917158