[Vue2.0 source code learning] Virtual DOM articles - virtual DOM in Vue

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 Vuewhat the virtual DOM is like.

2. Introduction to virtual DOM

Since this series of articles is aimed at Vuein-depth study of the source code, it focuses on analyzing Vuehow 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:

  1. What is virtual DOM?

    The so-called virtual DOM is to use an JSobject to describe a DOMnode, as in the following example:

    <div class="a" id="b">我是内容</div>
    
    {
          
          
      tag:'div',        // 元素标签
      attrs:{
          
                     // 属性
        class:'a',
        id:'b'
      },
      text:'我是内容',  // 文本内容
      children:[]       // 子元素
    }
    

    We express DOMthe 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 .JSJSDOMJSDOMDOM

  2. Why have a virtual DOM?

    We know that Vuethe view is driven by data, and the view must be updated when the data changes. It is inevitable to operate when updating the view, DOMand the operation DOMis actually very performance-consuming. This is because the browser standard DOMdesign very Complex, so a real DOMelement is very large, like this:

    let div = document.createElement('div')
    let str = ''
    for (const key in div) {
          
          
      str += key + ''
    }
    console.log(str)
    

insert image description here

In the image above we print a simple empty divlabel , and that's all it takes to print out, let alone complex, deeply nested DOMnodes. It can be seen that the real DOMnode data will occupy a larger memory. When we DOMupdate frequently, there will be certain performance problems, because DOMthe update of may cause page redrawing or rearrangement.

So is there any solution? Of course there are. We JScan trade the computational performance of for DOMthe performance consumed by the operation .

Since we can't escape DOMthe hurdle of operation, we can operate as little as possible DOM. So DOMhow ? 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 DOMdo . This is what is JSsaid in exchange for the computing performance of the operation DOMperformance.

We can use to JSsimulate a DOMnode, which is called a virtual DOMnode . When the data changes, we compare the virtual DOMnodes before and after the change, DOM-Diffcalculate 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 DOMof .

In addition, using a virtual can DOMalso make Vueis no longer dependent on the browser environment. We can easily operate virtual on Broswerthe client or server side, and then convert the virtual to real whenDOM needed . This also enables the ability to implement server-side rendering.renderDOMDOMVue

3. Virtual DOM in Vue

In the previous article, we introduced DOMthe concept of virtualization and why there is virtualization DOM, so how is Vuevirtualization DOMrealized in the Internet? Next, let's start from the source code and learn more about it.

3.1 VNode class

As we said, virtual DOMis JSused to describe a real DOMnode. And Vuethere is a VNodeclass in , through which we can instantiate different types of virtual DOMnodes, 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 VNodethe class contains DOMa series of attributes required to describe a real node, such as tagthe label name representing the node, textthe text contained in the node, childrenand 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, VNodeclasses can describe various types of real DOMnodes. 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: textand isComment. Among them, textthe attribute represents specific annotation information, isCommentwhich 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 textan 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 isClonedis true.

3.2.4 Element Node

In contrast, element nodes are closer to the real nodes we usually see . It has attributes DOMdescribing 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:tagclassattributesdatachildren

// 真实DOM节点
<div id='a'><span>难凉热血</span></div>

// VNode节点
{
    
    
  tag:'div',
  data:{
    
    },
  children:[
    {
    
    
      tag:'span',
      text:'难凉热血'
    }
  ]
}

We can see that DOMin the real node: divthe label contains a spanlabel, and spanthere is a piece of text in the label. The reaction to VNodethe node is as shown above: tagit indicates the label name, datathe attribute of the label, idetc., and childrenindicates 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, propsetc.
  • VuecomponentInstance : 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 VNodea variety of node types that can be described. They are essentially VNodeinstances 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 VNodein Zai play?VueDOM

In fact VNode, the role is quite large. templateBefore 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 VNodewith the previous cached one to find the difference. Then the real node corresponding to VNodethe 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.VNodeDOMVNodeDOM

4. Summary

This chapter first introduces DOMsome basic concepts of virtualization and why there is virtualization DOM. In fact, to put it bluntly, it is to JSexchange the computing performance for DOMthe performance consumed by the actual operation. Then from the perspective of source code, we know that different types of virtual nodes Vueare VNodeinstantiated 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 VNodeinstances of classes. , but the attribute parameters passed in during instantiation are different. Finally, after exploring VNodethe 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 DOMto save performance.

Guess you like

Origin blog.csdn.net/weixin_46862327/article/details/130675618