A brief analysis of Vue's asynchronous update of DOM

A brief analysis of Vue's asynchronous update of DOM

Data object: the object returned by the data method in vue;

Dep object: Each Data attribute will create a Dep to collect all Watcher objects that use this Data;

Watcher object: mainly used to render DOM

The principle of Vue asynchronously updating DOM

Data updates in Vue are asynchronous, which means that we cannot immediately obtain the modified DOM elements after modifying the Data.

1 When can we get the real DOM element?

in Vue's nextTick callback.

2 Why does Vue need to use the nextTick method to obtain the latest DOM?

2.1 When vue calls Watcher to update the view, it does not update directly, but adds the Watcher that needs to be updated to the Queue queue, and then passes the specific update method flushSchedulerQueue to nexTick for calling.

// src > core > observer > watcher.js + scheduler.js // When a Data is updated, the following code will be executed in sequence // 1. Trigger Data.set
// 2. Call dep.notify
// 3. Dep will traverse all related Watchers and execute the update method class Watcher {
  // 4. Execute update operation update() {
    queueWatcher(this);
  }
}

const queue = [];

function queueWatcher(watcher: Watcher) {
  // 5. Add the current Watcher to the asynchronous queue queue.push(watcher);
  // 6. Execute the asynchronous queue and pass in the callback nextTick(flushSchedulerQueue);
}

// Specific method for updating the view function flushSchedulerQueue() {
  let watcher, id;
  // Sort, render the parent node first, then render the child node // This can avoid unnecessary child node rendering, such as: the child node whose v-if is false in the parent node does not need to be rendered queue.sort((a, b) => a.id - b.id);
  // Traverse all Watchers for batch update.
  for (index = 0; index < queue.length; index++) {
    watcher = queue[index];
    // Update the DOM
    watcher.run();
  }
} 

2.2 nextTick -- Add the passed flushSchedulerQueue to the callbacks array and then execute the timerFunc method.

const callbacks = [];
let timerFunc;

function nextTick(cb?: Function, ctx?: Object) {
  let _resolve;
  // 1. Add the passed flushSchedulerQueue method to the callback array callbacks.push(() => {
    cb.call(ctx);
  });
  // 2. Execute asynchronous tasks // This method will select different asynchronous strategies timerFunc() according to browser compatibility;
}

2.3 timerFunc method - is an asynchronous method created based on browser compatibility. After executing this method, the flushSchedulerQueue method will be called to perform specific DOM updates.

let timerFunc;
// Determine whether it is compatible with Promise
if (typeof Promise !== "undefined") {
  timerFunc = () => {
    Promise.resolve().then(flushCallbacks);
  };
  // Determine whether it is compatible with MutationObserver
  // https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver
} else if (typeof MutationObserver !== "undefined") {
  let counter = 1;
  const observer = new MutationObserver(flushCallbacks);
  const textNode = document.createTextNode(String(counter));
  observer.observe(textNode, {
    characterData: true,
  });
  timerFunc = () => {
    counter = (counter + 1) % 2;
    textNode.data = String(counter);
  };
  // Determine whether it is compatible with setImmediate
  // This method exists in some IE browsers} else if (typeof setImmediate !== "undefined") {
  // This is a macro task, but better than setTimeout timerFunc = () => {
    setImmediate(flushCallbacks);
  };
} else {
  // If none of the above methods are known, use setTimeout 0
  timerFunc = () => {
    setTimeout(flushCallbacks, 0);
  };
}

// After asynchronous execution, execute all callback methods, that is, execute flushSchedulerQueue
function flushCallbacks() {
  for (let i = 0; i < copies.length; i++) {
    callbacks[i]();
  }
} 

2.4 Improve logical judgment

2.4.1 Determine the has flag to avoid adding the same Watcher to a Queue;

2.4.2 Determine the waiting flag and update all Watchers within one tick;

2.4.3 Determine the flushing flag and process the new Watcher that may be generated when the Watcher is rendered.

If the v-if condition is triggered, the newly added Watcher is rendered.

tip: nextTick is just an asynchronous task simulated by Promise, setTimeout and other methods.

3 Why can this.$nextTick get the updated DOM?

Calling this.$nextTick actually calls the nextTick method in the diagram and executes the callback function in the asynchronous queue. According to the first-in-first-out principle, the update asynchronous queue triggered by modifying Data will be executed first. After the execution is completed, a new DOM is generated. When the callback function of this.$nextTick is executed next, the updated DOM element can be obtained.

// We use this.$nextTick to call the nextTick method Vue.prototype.$nextTick = function (fn: Function) {
  return nextTick(fn, this);
};

Summary: The principle of Vue asynchronous update

When the Data in Vue is modified, all Watchers related to this Data will be triggered to update. First, all Watchers will be added to the queue. Then, call the nextTick method to perform asynchronous tasks. In the callback of the asynchronous task, sort the Watchers in the Queue and then perform the corresponding DOM updates.

This is the end of this article about the implementation of Vue asynchronous update of DOM. For more relevant Vue asynchronous update of DOM content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • VUE updates DOM asynchronously - using $nextTick to solve DOM view problems
  • Detailed explanation of asynchronous DOM update strategy and nextTick from Vue.js source code
  • Vue batch update dom implementation steps

<<:  Detailed tutorial on building nextcloud private cloud storage network disk

>>:  MySQL query statement process and basic concepts of EXPLAIN statement and its optimization

Recommend

19 MySQL optimization methods in database management

After MySQL database optimization, not only can t...

Getting Started Guide to MySQL Sharding

Preface Relational databases are more likely to b...

Detailed explanation of several methods of installing software in Linux

1. RPM package installation steps: 1. Find the co...

IDEA uses the Docker plug-in (novice tutorial)

Table of contents illustrate 1. Enable Docker rem...

Core skills that web front-end development engineers need to master

The content involved in Web front-end development...

In-depth analysis of MySQL data type DECIMAL

Preface: When we need to store decimals and have ...

A brief discussion on JS regular RegExp object

Table of contents 1. RegExp object 2. Grammar 2.1...

Two ways to specify the character set of the html page

1. Two ways to specify the character set of the h...

JavaScript to implement limited time flash sale function

This article shares the specific code of JavaScri...

Introduction to Linux system swap space

Swap space is a common aspect of computing today,...

How to use squid to build a proxy server for http and https

When we introduced nginx, we also used nginx to s...

Deploy Nginx+Flask+Mongo application using Docker

Nginx is used as the server, Mongo is used as the...

Implementation of MySQL multi-version concurrency control MVCC

Transaction isolation level settings set global t...