What is VDOM?
In Web development, data changes need to be reflected on the UI in real time. In this case, DOM operations need to be performed. However, complex or frequent DOM operations often cause performance bottlenecks.
Vdom is the abbreviation of Virtual DOM(Virtual DOM). It refers to the DOM structure simulated by JS, and the comparison of DOM changes is done on the JS layer. In other words, A VDOM is a JS object.
DOM structure:
<ul id="list">
<li class="item">Item1</li>
<li class="item">Item2</li>
</ul>
Copy the code
Mapping to a virtual DOM looks like this:
{tag: "ul", attrs: {id:"list"}, children: [{tag: "li", attrs: {className: "item"}, children: ["Item1"] }, { tag: "li", attrs: { className: "item" }, children: ["Item2"] } ] }Copy the code
What is vDOM useful for?
The virtual DOM is a highlight of React, with batching and efficient Diff algorithms. This allows us to “refresh” the entire page at any time without worrying about performance, and the virtual DOM ensures that only the parts of the interface that actually change are actually DOM manipulated. How the virtual DOM works is virtually unnecessary in actual development, but understanding how it works not only helps you better understand the life cycle of the React component, but also helps you optimize the React application.
Here’s an example
Now there is a scenario that implements the following requirements:
[{name: "zhang", the age: "20", address: "Beijing"}, {name: "bill", the age: "21," address: "wuhan"}, {name: "detective", the age: "22", address: "Hangzhou"},]Copy the code
Present this data as a table, and modify any information you want, and the table will change as well. JQuery implementation is as follows:
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, <meta HTTP-equiv =" x-UA-compatible "content=" IE =edge"> <title>Document</title> </head> <body> <div Id ="container"></div> <button id="btn-change"> change </button> <script SRC = "https://cdn.bootcss.com/jquery/3.2.0/jquery.js" > < / script > < script > const data = ({name: "zhang", the age: "20", address: "Beijing"}, {name: "bill", the age: "21," address: "wuhan"}, {name: "detective", the age: "22", address: "hangzhou"},]; Function render(data) {const $container = $('#container'); $container.html(''); const $table = $('<table>'); / / redraw a $table. Append ($(" < tr > < td > name < / td > < td > age < / td > < td > address < / td > < / tr > ')); Data. forEach(item => {// redraw each entry $table.append($(`<tr><td>${item.name}</td><td>${item.age}</td><td>${item.address}</td></tr>`)) }) $container.append($table); } $('#btn-change').click(function () { data[1].age = 30; Data [2]. Address = 'shenzhen '; render(data); }); </script> </body> </html>Copy the code
Click on the button, so there will be a corresponding view changes, but you review the following elements, after each change, table tags have to recreate, every column that is under the table, whether the data is the same, it will have to apply colours to a drawing, it’s not an ideal situation, when one of the column data as well as the original, We would prefer that this column not be re-rendered, because DOM redrawing is quite a drain on browser performance.
Therefore, we adopt the METHOD of JS object simulation, and put the DOM comparison operation in the JS layer to reduce unnecessary redrawing of the browser and improve efficiency.
Of course, some people say that the virtual DOM is no faster than the real DOM, and there is truth to that. When each item in the table above changes, it is obvious that the real DOM is faster because the virtual DOM also has the comparison process of the DIff algorithm in JS. Therefore, the above performance benefits only apply when rendering a large amount of data and changing only a small fraction of the data.
What makes the virtual DOM even better is:
1. It opens the door to functional UI programming, the way UI = F (data) is built.
2. Render JS objects to environments outside the BROWSER DOM, which supports cross-platform development such as ReactNative.
3. Use SNabbDOM to achieve VDOM
Snabbdom address: github.com/snabbdom/sn…
This is a simple library to implement vDOM functions. Compared with VUE and React, it is easier for us to learn VDOM.
There are two core APIS in VDOM, one is h function, the other is patch function, which is used to generate VDOM objects. The latter function is to do virtual DOM comparison and mount vDOM to the real DOM.
A brief introduction to the use of these two functions: -h (‘ label name ‘, {attribute}, [child element]) -h (‘ Label name ‘, {attribute}, [text]) -patch (container, vnode) Container is a container DOM element – patch(vnode, newVnode)
Now let’s rewrite the example using snabbdom:
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, <meta HTTP-equiv =" x-UA-compatible "content=" IE =edge"> <title>Document</title> </head> <body> <div Id ="container"></div> <button id="btn-change"> change </button> <script SRC = "https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom.js" > < / script > < script SRC = "https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-class.js" > < / script > < script SRC = "https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-props.js" > < / script > < script SRC = "https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-style.js" > < / script > < script SRC = "https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-eventlisteners.min.js" > < / script > < script SRC = "https://cdn.bootcss.com/snabbdom/0.7.3/h.js" > < / script > < script > let snabbdom = window. Snabbdom; Patch let patch = snabbdom.init([snabbdom_class, snabbdom_props, snabbdom_style, snabbdom_eventlisteners]); // define h let h = snabbdom.h; Const data = [{name: "zhang", the age: "20", address: "Beijing"}, {name: "bill", the age: "21," address: "wuhan"}, {name: "detective", the age: "22", address: "hangzhou ",]; Data. The unshift ({name: "name", the age: "age", address: "address"}); let container = document.getElementById('container'); let vnode; const render = (data) => { let newVnode = h('table', {}, data.map(item => { let tds = []; for(let i in item) { if(item.hasOwnProperty(i)) { tds.push(h('td', {}, item[i] + '')); } } return h('tr', {}, tds); })); if(vnode) { patch(vnode, newVnode); } else { patch(container, newVnode); } vnode = newVnode; } render(data); let btnChnage = document.getElementById('btn-change'); btnChnage.addEventListener('click', function() { data[1].age = 30; Data [2]. Address = "shenzhen "; //re-render render(data); }) </script> </body> </html>Copy the code
On the page, you’ll notice that only the columns that have changed are flashing, that is, redrawn, and the columns that have not changed are left as they are, saving the browser a lot of rerendering overhead.
Diff algorithm
Without the Virtual DOM, it’s simply a matter of resetting innerHTML. This is fine in the case of a large list where all the data changes, but when only one row changes, it also needs to reset the entire innerHTML, which is obviously wasteful.
Comparing innerHTML with the Virtual DOM redrawing process is as follows:
- InnerHTML: Render HTML string + recreates all DOM elements
- Virtual DOM: Render Virtual DOM + diff + necessary DOM updates
Js computation is very cheap compared to DOM manipulation. Virtual DOM Render + diff is obviously slower than rendering HTML strings, but it’s still pure JS level computation and much cheaper than the DOM manipulation behind it.
React. Js has significant performance advantages over direct manipulation of the native DOM, thanks in large part to the batching and diff of the Virtual DOM. Batching collects all the DOM operations and submits them to the real DOM at once. The time complexity of diFF algorithm is reduced from O(n^3) of standard DIFF algorithm to O(n).
1. What is diff algorithm?
The diff algorithm is an algorithm used to find the difference between two paragraphs of text.
As a front-end, we often hear the word diff algorithm, in fact, is not the front-end original algorithm, in fact, this algorithm has long been reflected in the Linux diff command, and everyone commonly used git diff is also using the diff algorithm.
2. Why does VDOM use diff algorithm
DOM manipulation is very expensive, so we need to minimize DOM manipulation. In this case, it is necessary to find out which nodes the DOM must update, and not to update the others. In this process, it is necessary to apply the DIff algorithm.
3. Simple implementation of DIFF algorithm in VDOM
Ideas:
Algorithm implementation
- Step 1: Simulate the DOM tree with JS objects
- Step 2: Compare the differences between the two virtual DOM trees
- Step 3: Apply the difference to a real DOM tree
The following code is intended to help you understand the principles and flow of the DIff algorithm and is not intended for use in production environments.
Convert vDOM to real DOM:
const createElement = (vnode) => { let tag = vnode.tag; let attrs = vnode.attrs || {}; let children = vnode.children || []; if(! tag) { return null; } // createElement let elem = document.createelement (tag); // attribute let attrName; for (attrName in attrs) { if(attrs.hasOwnProperty(attrName)) { elem.setAttribute(attrName, attrs[attrName]); ForEach (childVnode => {// Add child elem. AppendChild (createElement(childVnode)); }) // Return the real DOM element. }Copy the code
Update operation with simple diff algorithm:
function updateChildren(vnode, newVnode) { let children = vnode.children || []; let newChildren = newVnode.children || []; children.forEach((childVnode, index) => { let newChildVNode = newChildren[index]; If (childvNode. tag === newChildvNode. tag) {// For further contrast, the recursion process updateChildren(childVnode, newChildVNode); } else {// Replace replaceNode(childVnode, newChildVNode); }})}Copy the code
Recommended article: www.alloyteam.com/2015/10/rea…
www.zhihu.com/question/31…