SoFunction
Updated on 2025-04-04

Detailed explanation of Vue2 asynchronous update and nextTick principle

vueThis is how nextTick is described in the official website

Execute a delayed callback after the next DOM update loop ends. Use this method immediately after modifying the data to obtain the updated DOM.

Before learning how nextTick is implemented, we need to understand the execution mechanism of JavaScript

JavaScript execution mechanism

Browsers are multi-threaded, such as GUI rendering threads, JS engine threads, event listening threads, etc. . .

The javascript execution mechanism is implemented by borrowing the browser's multi-threaded mechanism and then based on the Event Loop event loop mechanism. It realizes a single thread asynchronous effect

The steps for Event Loop are roughly as follows:

When the browser loads the page, in addition to opening up the stack memory, two queues will be created. Web API: Task listening queue, monitoring whether asynchronous tasks can be executed. Task Queue: Task queue, divided into asynchronous macro task queue and asynchronous micro task queue. When the main thread executes code from top to bottom, if asynchronous code is encountered, the asynchronous tasks will be placed in the Web API to listen. The browser will open a new thread to listen to whether it can be executed. It will not hinder the rendering of the main thread. It will continue to execute synchronous code downward. When the asynchronous task is monitored to be executed (with the result of the operation), it will not be executed immediately. Instead, an event is placed in the task queue, waiting for execution. Depending on the micro task or the macro task, it is placed in different queues. Who comes in first and who is at the front of their respective teams. All synchronous tasks in the execution stack are executed and the main thread is idle. At this time, the queued events will be taken out in the task queue in order, and the main thread will be executed. The micro-task has a higher priority. When the execution stack is empty, first execute events in the micro-task queue. Only when the micro-task queue is empty will the events in the macro-task queue be executed. The above process will be repeated continuously, which is commonly known as the Event Loop (Event Loop)

Tasks are divided into two categories: macro tasks and micro tasks.

Common macro tasks include script (the overall code),setTimeout/setInterval/setImmediateXMLHttpRequest/fetch, DOM events (such as mouse click, scrolling page, zooming in and out, etc.), rendering events (parse DOM, calculate layout, draw) Common micro tasks include/catch/finallyasync/awaitMutationObserver

What needs to be noted! ! ! If a new micro-task is added during the process of processing micro-tasks, the addition speed is always faster than execution, then the micro-tasks will be executed forever

The following code will never print the macro task output

function macroFn(){
   setTimeout(() => {
     ('>>>>MA')
   },0)
}
function microFn(){
    ().then(() => {
        ('mi')
        microFn()
    })
}
macroFn()
microFn()

nextTick implementation principle

In the vue2.7 source code, there is a separate filesrc/core/util/To maintain nextTick, students who are interested can watch it on their own

In the vue2.7 source code, nextTick does not directly use a certain API, but uses an elegant downgrade solution to achieve asynchronous updates.

Inside, I will try to use native(IE does not support)MutationObserverandsetImmediate (exclusive to higher version IE)If the execution environment does not support it, it will be usedsetTimeout(fn, 0)

It should be noted that we maintain a callbacks for storing nextTick callbacks

This ensures that nextTick is called multiple times within the same tick. Just create an asynchronous task and you can execute all nextTick callbacks in callbacks in sequence. Instead of starting multiple asynchronous tasks to handle.

let callbacks = [] //Storage nextTick callbacklet waiting = false // Anti-shake
// Execute the methods in callbacks in sequencefunction flushCallbacks() {
  let cbs = (0)
  waiting = false
  callbacks = []
  (cb => cb()) 
}


let timerFunc;
if (Promise) {
    timerFunc = () => {
        ().then(flushCallbacks)
    }
}else if(MutationObserver){
    let observer = new MutationObserver(flushCallbacks); // The callbacks passed here are executed asynchronously    let textNode = (1);
    (textNode,{
        characterData:true
    });
    timerFunc = () => {
         = 2;
    }
}else if(setImmediate){
    timerFunc = () => {
       setImmediate(flushCallbacks);
    }
}else{
    timerFunc = () => {
        setTimeout(flushCallbacks);
     }
}

export function nextTick(cb) {
  (cb) // Maintain the cakllback method in nextTick  
  if (!waiting) {
    timerFunc()
    waiting = true
  }
}

Asynchronous update

Asynchronous update rendering inside vue also uses nextTick

In the update update method of the Watcher class, we call the queueWatcher asynchronous queue update method, which is in the vue2.7 source codesrc/core/util/Maintenance in the file

import { queueWatcher } from './scheduler'

class Watcher {
	...
  // Re-render  update() {
    ('watcher-update')
    queueWatcher(this) // watcher asynchronous update  }
}

src/core/util/

import { nextTick } from '../util/next-tick'

/**
  * @name QueueWatcher, internal watcher is updated asynchronously
  * @decs Save the current watcher temporarily. In a tick cycle, no matter how many times our update is executed, it will only perform a round of refresh operations.
  */

let queue = []
let has = {}
let pending = false // Anti-shake
function flushSchedulerQueue() {
  let flushQueue = (0)
  queue = []
  has = {}
  pending = false
  (q => ()) // There may be a new watcher during the refresh process, and it will be re-placed into the queue}

// In a tick cycle, no matter how many times our update is performed, only one round of refresh operations will be performed.export function queueWatcher(watcher) {
  const id = 
  if (!has[id]) {
    (watcher)
    has[id] = true
    if (!pending) {
      nextTick(flushSchedulerQueue)
      pending = true
    }
  }
}

Frequently Asked Questions

1. Is nexTick asynchronous or synchronous?

This cannot be generalized. NextTick has both synchronous and asynchronous code.

For example, maintaining the callbacks queue is a synchronous task; the method in the queue is an asynchronous task

2. Is the nextTick callback execution micro-task or macro-task?

For vue2.7, nextTick does not directly use a certain API, but uses an elegant downgrade solution to achieve asynchronous updates.
Inside, I will try to use native(Micro Task)MutationObserver (Micro Tasks)andsetImmediate (macro task)If the execution environment does not support it, it will be usedsetTimeout (macro task)

It can be understood that in 99% of the scenarios, it is a macro task only in browsers that do not support the Promise and MutationObserver APIs, such as IE9 and IE10

3. Why encapsulate nextTick? Instead of using a specific API?

Elegant downgrade. Try to use micro-tasks to shorten the rendering cycle as much as possible

Ensure unity. nextTick can be exposed to users, ensuring that users use this method immediately after modifying data, and can obtain the updated DOM

 = 'libc'

this.$nextTick(()=>{
  (('.user').innerHTML)
});

Summarize:

Vue2's asynchronous update mechanism is one of the core of Vue, and it achieves efficient rendering and performance optimization through the event loop mechanism. The nextTick method provides a more flexible DOM operation method, and can execute callback functions after DOM is updated. When developing with Vue2, it is very necessary to understand and master the asynchronous update mechanism and nextTick method, which can help us better optimize performance and improve rendering efficiency.

This is the end of this article about the detailed explanation of Vue2 asynchronous update and nextTick principle. For more related contents of Vue2 asynchronous update and nextTick principle, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!