Those of you familiar with Vue know that Vue has a nextTick method that updates data asynchronously.

Take a look at this chestnut:

<body>
    <div id="main">
        <ul class="list">
            <li class="item" v-for="item in list">{{ item }}</li>
        </ul>
    </div>
    
    <script>
        new Vue({
            el: '#main',
            data: {
                list: [
                    'AAAAAAAAAA'.'BBBBBBBBBB'.'CCCCCCCCCC'
                ]
            },
            mounted: function (a) {
                this.list.push('DDDDD')}})</script>
</body>
Copy the code

After some arbitrary styling, the page looks like this:

    mounted: function () {
        this.list.push('DDDDD')
        console.log(this.$el.querySelectorAll('.item').length)  / / 3
    }
Copy the code

    mounted: function () {
        this.list.push('DDDDD')
        Vue.nextTick(function() {
            console.log(this.$el.querySelectorAll('.item').length)  / / 4
            / /... To calculate
        })
Copy the code

When you set vm.someData = 'new Value ', the component does not immediately re-render. When the queue is refreshed, the component updates with the next "tick" when the event loop queue is empty. In most cases we don't need to worry about this process, but if you want to do something after a DOM status update, it can be tricky. While vue.js generally encourages developers to think in a "data-driven" way and avoid direct contact with the DOM, sometimes we do. To wait for Vue to finish updating the DOM after the data changes, use vue.nexttick (callback) immediately after the data changes. This callback will be called after the DOM update is complete.

Simply put, the DOM is updated at least until all code in the current thread has been executed. Therefore, it is not possible to execute a piece of code after modifying the data and DOM updating. To ensure that a piece of code is executed after DOM updating, it must be placed in the next event loop, such as setTimeout(fn, 0), so that it will be executed immediately after DOM updating.

Highlight: queues, event loops

Js is a single-threaded language

As we all know, all tasks executed by JS need to be queued, and a task must wait for the task before it to complete. If the former task takes a lot of time to compute, then the latter task must wait for it to complete before it is ready to execute, such is the nature of single-threading. Js tasks are divided into two types, synchronous tasks and asynchronous tasks:

  • Synchronization tasks are executed one by one in sequence. The latter task must wait until the previous task completes
  • Asynchronous tasks (such as callbacks) do not occupy the main thread. Instead, they are placed in a task queue, and when the main thread is finished, the tasks in the asynchronous task queue are put back to the main thread for execution

Here’s an ugly but understandable graph:

Event Loop

It is called an event loop because synchronized tasks may generate new tasks, so it is constantly looking for new events and executing them. The execution of a loop is called a TICK, the code executed within the loop is called a Task, and the process is repeated.

console.log(1);

setTimeout((a)= >{
  console.log(2);
},1000);

while (true) {}Copy the code

The above code is printed after 1 (use caution! My browser is stuck ~), the timer is stuck in the queue, and then the main thread continues to execute, hitting an infinite loop that causes the task in the queue to never be executed, so 2 is not printed

The event queue

In addition to our main thread, task queues are divided into microtasks and macrotasks, which are commonly referred to as microtasks and macro tasks. The term microtask is a relatively new concept in JS, and we usually first encountered it when learning ES6 Promise.

  • In the execution priority, main thread task > MicroTask > MacroTask.
  • Typical MacroTasks include setTimeout and setInterval, As well as setImmediate, which is supported only by IE, and MessageChannel. ES6 promises are microTasks

console.log(1)

setTimeout(function(){
	console.log(2)})Promise.resolve().then(function(){
	console.log('promise1')
}).then(function(){
	console.log('promise2')})console.log(4)

Copy the code

Depending on the order of execution, the output of the above code can be easily obtained:

nextTick

To return to the topic above, Vue’s nextTick method internally attempts to use native setImmediate Promise. Then and MessageChannel for asynchronous queues, if not supported by the current implementation environment. Use setTimeout(fn, 0) instead.

Nodejs

Node natively supports the process.Nexttick (FN) and setImmediate(FN) methods, and process.Nexttick (FN) is executed sequentially as a microtask.