Deep dive into the virtual DOM (vdom) at the core of vue

1. The real DOM and its analysis process?
The workflow of the browser rendering engine is similar, roughly divided into 5 steps, creating a DOM tree-creating StyleRules-creating a Render tree-Layout-drawing Painting

第一步,用HTML分析器,分析HTML元素,构建一颗DOM树(标记化和树构建)。

第二步,用CSS分析器,分析CSS文件和元素上的inline样式,生成页面的样式表。

第三步,将DOM树和样式表,关联起来,构建一颗Render树(这一过程又称为Attachment)。每个DOM节点都有attach方法,接受样式信息,返回一个render对象(又名renderer)。这些render对象最终会被构建成一颗Render树。

第四步,有了Render树,浏览器开始布局,为每个Render树上的节点确定一个在显示屏上出现的精确坐标。

第五步,Render树和节点显示坐标都有了,就调用每个节点paint方法,把它们绘制出来。 

DOM树的构建是文档加载完成开始的?构建DOM数是一个渐进过程,为达到更好用户体验,渲染引擎会尽快将内容显示在屏幕上。它不必等到整个HTML文档解析完毕之后才开始构建render数和布局。

Render树是DOM树和CSSOM树构建完毕才开始构建的吗?这三个过程在实际进行的时候又不是完全独立,而是会有交叉。会造成一边加载,一遍解析,一遍渲染的工作现象。

CSS的解析是从右往左逆向解析的(从DOM树的下-上解析比上-下解析效率高),嵌套标签越多,解析越慢。

Insert picture description here

Workflow of webkit rendering engine
2. The cost of JS operating real DOM!
When we use our traditional development model, native JS or JQ to manipulate the DOM, the browser will execute the process from beginning to end from the beginning of building the DOM tree. In one operation, I need to update 10 DOM nodes. After receiving the first DOM request, the browser does not know that there are 9 update operations, so it will execute the process immediately, and finally execute 10 times. For example, after the first calculation is completed, immediately following the next DOM update request, the coordinate value of this node changes, and the previous calculation is useless. Calculating the DOM node coordinate value and so on is a waste of performance. Even if the computer hardware has been iteratively updated, the cost of operating the DOM is still expensive, and frequent operations will still cause page freezes, which will affect the user experience.

3. Why do you need a virtual DOM, and what are its benefits? The
web interface is constructed by a DOM tree (tree means data structure). When a part of it changes, it is actually a corresponding DOM node that has changed.

    虚拟DOM就是为了解决浏览器性能问题而被设计出来的。如前,若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,用JS对象模拟DOM节点的好处是,页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。

Fourth, implement a virtual DOM
such as a real DOM node.
Real DOM

    我们用JS来模拟DOM节点实现虚拟DOM。

Virtual DOM

    其中的Element方法具体怎么实现的呢?

Element method implementation

    第一个参数是节点名(如div),第二个参数是节点的属性(如class),第三个参数是子节点(如ul的li)。除了这三个参数会被保存在对象上外,还保存了key和count。其相当于形成了虚拟DOM树。

Virtual DOM tree

    有了JS对象后,最终还需要将其映射成真实DOM

Virtual DOM objects are mapped to real DOM

    我们已经完成了创建虚拟DOM并将其映射成真实DOM,这样所有的更新都可以先反应到虚拟DOM上,如何反应?需要用到Diff算法。

    两棵树如果完全比较时间复杂度是O(n^3),但参照《深入浅出React和Redux》一书中的介绍,React的Diff算法的时间复杂度是O(n)。要实现这么低的时间复杂度,意味着只能平层的比较两棵树的节点,放弃了深度遍历。这样做,似乎牺牲掉了一定的精确性来换取速度,但考虑到现实中前端页面通常也不会跨层移动DOM元素,这样做是最优的。

    深度优先遍历,记录差异
    。。。。

    Diff操作
    在实际代码中,会对新旧两棵树进行一个深度的遍历,每个节点都会有一个标记。每遍历到一个节点就把该节点和新的树进行对比,如果有差异就记录到一个对象中。

    下面我们创建一棵新树,用于和之前的树进行比较,来看看Diff算法是怎么操作的。

old Tree

new Tree

For leveling Diff, there are only the following 4 situations:

1. The node type has changed . For example, P in the figure below has changed to H3. We call this process REPLACE . Unload the old node directly and load the new node. The old node including the child nodes below will be uninstalled. If the new node and the old node are only of different types, but all the child nodes below are the same, this is not efficient. But in order to avoid O(n^3) time complexity, it is worth it. This also reminds developers that they should avoid unnecessary changes in node types, for example, it makes no sense to change div to p at runtime.

2. The node type is the same, only the attribute or attribute value has changed . We call this process PROPS . At this time, node unloading and loading will not be triggered, but node update.
Find different attribute methods

3. The text has changed . The text pair is also a Text Node, which is relatively simple. Just modify the text content directly. We call this process TEXT.

4. Move/add/delete child nodes . We call this process REORDER. Look at an example, add an F node between the two nodes B and C of the five nodes A, B, C, D, and E.
Insert picture description here

Example
Our simple and rude approach is to traverse each node of the new virtual DOM, compare it with the corresponding node of the old virtual DOM, whether it exists in the old DOM, uninstall the original one and press the new one. This will operate on every node behind F. Unload C, load F, unload D, load C, unload E, load D, load E. The efficiency is too low .
Crude practice

    如果我们在JSX里为数组或枚举型元素增加上key后,它能够根据key,直接找到具体位置进行操作,效率比较高。常见的最小编辑距离问题,可以用Levenshtein Distance算法来实现,时间复杂度是O(M*N),但通常我们只要一些简单的移动就能满足需要,降低精确性,将时间复杂度降低到O(max(M,N))即可。

The final result of Diff

Mapping to real DOM
Virtual DOM is available, so does Diff, and now Diff can be applied to real DOM. Deeply traverse the DOM to update the content of the Diff.
Update DOM based on Diff
Update DOM based on Diff

We will have two virtual DOMs (js object, new/old to compare diff), user interaction, we manipulate the data to change the new virtual DOM, the old virtual DOM will be mapped to the actual DOM (DOM document generated by the js object) through the DOM fragment operation Browser rendering. When the new virtual DOM is modified, the newDOM and oldDOM will be compared through the diff algorithm to get the diff result data table (represented by 4 kinds of transformations). Then update the diff result table to the browser DOM through the DOM fragment.

The meaning of the existence of virtual DOM? The real meaning of vdom is to achieve cross-platform, server-side rendering, and to provide a Dom update strategy with fairly good performance. vdom makes the entire mvvm framework flexible

The Diff algorithm is just to compare and replace the virtual DOM with higher efficiency. The Diff algorithm is used to obtain the result data table of the diff algorithm (recording table of what operations are required). The original DOM to be manipulated still needs to be manipulated on the vue side, but the DOM fragment of js is used to manipulate the dom (a unified update of the DOM after all the changes are calculated uniformly) for a one-time update of the browser DOM. In fact, we can use DOM fragments without having to publish them normally, but in this way, programmers can write business codes by putting DOM operations into fragments. This is the value of the framework and programmers can focus on writing business codes.

Guess you like

Origin blog.csdn.net/weixin_45895806/article/details/109715064