Article directory
1 Introduction
Virtual DOM, this term, as a current front-end developer, you must be familiar with it, at least you have heard it a little bit, but it is not unheard of. This is also a very high-frequency test site in job interview inspections. Because the virtual DOM is more or less involved in the current three front-end frameworks, so next, we will start from the source code point of view to see Vue
what the virtual DOM is like.
2. Introduction to virtual DOM
Since this series of articles is aimed at Vue
in-depth study of the source code, it focuses on analyzing Vue
how the virtual DOM is realized in the middle, and does not discuss the concept of the virtual DOM itself in a large space, but only briefly introduces the following questions:
-
What is virtual DOM?
The so-called virtual DOM is to use an
JS
object to describe aDOM
node, as in the following example:<div class="a" id="b">我是内容</div> { tag:'div', // 元素标签 attrs:{ // 属性 class:'a', id:'b' }, text:'我是内容', // 文本内容 children:[] // 子元素 }
We express
DOM
the necessary things that make up a node through an object, then this object can be used to describe this node, and we call this object a virtual node of this real node .JS
JS
DOM
JS
DOM
DOM
-
Why have a virtual DOM?
We know that
Vue
the view is driven by data, and the view must be updated when the data changes. It is inevitable to operate when updating the view,DOM
and the operationDOM
is actually very performance-consuming. This is because the browser standardDOM
design very Complex, so a realDOM
element is very large, like this:let div = document.createElement('div') let str = '' for (const key in div) { str += key + '' } console.log(str)
In the image above we print a simple empty div
label , and that's all it takes to print out, let alone complex, deeply nested DOM
nodes. It can be seen that the real DOM
node data will occupy a larger memory. When we DOM
update frequently, there will be certain performance problems, because DOM
the update of may cause page redrawing or rearrangement.
So is there any solution? Of course there are. We JS
can trade the computational performance of for DOM
the performance consumed by the operation .
Since we can't escape DOM
the hurdle of operation, we can operate as little as possible DOM
. So DOM
how ? The most intuitive idea is that we should not blindly update the view, but calculate which parts of the view need to be updated by comparing the state before and after the data change, and only update the parts that need to be updated, and do not care about the parts that do not need to be updated. This way we can DOM
do . This is what is JS
said in exchange for the computing performance of the operation DOM
performance.
We can use to JS
simulate a DOM
node, which is called a virtual DOM
node . When the data changes, we compare the virtual DOM
nodes before and after the change, DOM-Diff
calculate the place that needs to be updated through the algorithm, and then update the view that needs to be updated.
This is the reason and the biggest use DOM
of .
In addition, using a virtual can DOM
also make Vue
is no longer dependent on the browser environment. We can easily operate virtual on Broswer
the client or server side, and then convert the virtual to real whenDOM
needed . This also enables the ability to implement server-side rendering.render
DOM
DOM
Vue
3. Virtual DOM in Vue
In the previous article, we introduced DOM
the concept of virtualization and why there is virtualization DOM
, so how is Vue
virtualization DOM
realized in the Internet? Next, let's start from the source code and learn more about it.
3.1 VNode class
As we said, virtual DOM
is JS
used to describe a real DOM
node. And Vue
there is a VNode
class in , through which we can instantiate different types of virtual DOM
nodes, the source code is as follows:
// 源码位置:src/core/vdom/vnode.js
export default class VNode {
constructor (
tag?: string,
data?: VNodeData,
children?: ?Array<VNode>,
text?: string,
elm?: Node,
context?: Component,
componentOptions?: VNodeComponentOptions,
asyncFactory?: Function
) {
this.tag = tag /*当前节点的标签名*/
this.data = data /*当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息*/
this.children = children /*当前节点的子节点,是一个数组*/
this.text = text /*当前节点的文本*/
this.elm = elm /*当前虚拟节点对应的真实dom节点*/
this.ns = undefined /*当前节点的名字空间*/
this.context = context /*当前组件节点对应的Vue实例*/
this.fnContext = undefined /*函数式组件对应的Vue实例*/
this.fnOptions = undefined
this.fnScopeId = undefined
this.key = data && data.key /*节点的key属性,被当作节点的标志,用以优化*/
this.componentOptions = componentOptions /*组件的option选项*/
this.componentInstance = undefined /*当前节点对应的组件的实例*/
this.parent = undefined /*当前节点的父节点*/
this.raw = false /*简而言之就是是否为原生HTML或只是普通文本,innerHTML的时候为true,textContent的时候为false*/
this.isStatic = false /*静态节点标志*/
this.isRootInsert = true /*是否作为跟节点插入*/
this.isComment = false /*是否为注释节点*/
this.isCloned = false /*是否为克隆节点*/
this.isOnce = false /*是否有v-once指令*/
this.asyncFactory = asyncFactory
this.asyncMeta = undefined
this.isAsyncPlaceholder = false
}
get child (): Component | void {
return this.componentInstance
}
}
It can be seen from the above code that VNode
the class contains DOM
a series of attributes required to describe a real node, such as tag
the label name representing the node, text
the text contained in the node, children
and the child nodes contained in the node. Various types of real nodes can be described through different combinations of attributes DOM
.
3.2 Types of VNodes
At the end of the previous section, we said that through different combinations of attributes, VNode
classes can describe various types of real DOM
nodes. So what types of nodes can it describe? By reading the source code, we can find that the following types of nodes can be described through the combination of different attributes.
- comment node
- text node
- element node
- component node
- Functional Component Node
- clone node
Next, we will map these types of node description methods from the source code one by one.
3.2.1 Comment node
The comment node is relatively simple to describe. It only needs two attributes. The source code is as follows:
// 创建注释节点
export const createEmptyVNode = (text: string = '') => {
const node = new VNode()
node.text = text
node.isComment = true
return node
}
As can be seen from the above code, only two attributes are needed to describe a comment node, namely: text
and isComment
. Among them, text
the attribute represents specific annotation information, isComment
which is a flag used to identify whether a node is an annotation node.
3.2.2 Text nodes
A text node is simpler to describe than a comment node, because it only needs one attribute, which is text
an attribute, which is used to represent specific text information. The source code is as follows:
// 创建文本节点
export function createTextVNode (val: string | number) {
return new VNode(undefined, undefined, undefined, String(val))
}
3.2.3 Clone Node
Cloning a node is to copy an existing node. It is mainly used for template compilation and optimization, which we will talk about later. Regarding the description of the clone node, the source code is as follows:
// 创建克隆节点
export function cloneVNode (vnode: VNode): VNode {
const cloned = new VNode(
vnode.tag,
vnode.data,
vnode.children,
vnode.text,
vnode.elm,
vnode.context,
vnode.componentOptions,
vnode.asyncFactory
)
cloned.ns = vnode.ns
cloned.isStatic = vnode.isStatic
cloned.key = vnode.key
cloned.isComment = vnode.isComment
cloned.fnContext = vnode.fnContext
cloned.fnOptions = vnode.fnOptions
cloned.fnScopeId = vnode.fnScopeId
cloned.asyncMeta = vnode.asyncMeta
cloned.isCloned = true
return cloned
}
As can be seen from the above code, cloning a node is to copy all the attributes of the existing node to the new node, and the only difference between the existing node and the newly cloned node is that the cloned node isCloned
is true
.
3.2.4 Element Node
In contrast, element nodes are closer to the real nodes we usually see . It has attributes DOM
describing node label names , attributes describing node attributes such as , etc. , and attributes describing the information of child nodes contained in it . Since the situation contained in the element node is relatively complicated, the source code is not directly written to death like the first three nodes (of course it is impossible to write to death), so let me give a simple example to illustrate:tag
class
attributes
data
children
// 真实DOM节点
<div id='a'><span>难凉热血</span></div>
// VNode节点
{
tag:'div',
data:{
},
children:[
{
tag:'span',
text:'难凉热血'
}
]
}
We can see that DOM
in the real node: div
the label contains a span
label, and span
there is a piece of text in the label. The reaction to VNode
the node is as shown above: tag
it indicates the label name, data
the attribute of the label, id
etc., and children
indicates the array of child nodes.
3.2.5 Component nodes
In addition to the attributes of element nodes, component nodes also have two unique attributes:
- componentOptions : option options of components, such as components,
props
etc. Vue
componentInstance : the instance corresponding to the current component node
3.2.6 Functional component nodes
Compared with component nodes, functional component nodes have two unique properties:
- fnContext: the Vue instance corresponding to the functional component
- fnOptions: option option of the component
3.2.7 Summary
The above are VNode
a variety of node types that can be described. They are essentially VNode
instances of classes, but the attribute parameters passed in during instantiation are different.
3.3 The role of VNodes
Having said so much, what role did the whole virtual process VNode
in Zai play?Vue
DOM
In fact VNode
, the role is quite large. template
Before the view is rendered, we compile and cache the written template first VNode
. When the data changes and the page needs to be re-rendered, we compare the data generated after the data change VNode
with the previous cached one to find the difference. Then the real node corresponding to VNode
the difference is the node that needs to be re-rendered, and finally the real node is created according to the difference and inserted into the view, and finally a view update is completed.VNode
DOM
VNode
DOM
4. Summary
This chapter first introduces DOM
some basic concepts of virtualization and why there is virtualization DOM
. In fact, to put it bluntly, it is to JS
exchange the computing performance for DOM
the performance consumed by the actual operation. Then from the perspective of source code, we know that different types of virtual nodes Vue
are VNode
instantiated through classes DOM
, and we have learned the differences in the attributes generated by different types of nodes. The essence of the so-called different types of nodes is still the same, and they are all VNode
instances of classes. , but the attribute parameters passed in during instantiation are different. Finally, after exploring VNode
the role of the data before and after the change VNode
, we can find out the difference in the follow-up DOM-Diff
, and finally only update the view with the difference, so as to achieve the purpose of operating as little as possible DOM
to save performance.