The article was originally posted on my blog

Recently I found a lot of interview questions inside have “virtual DOM” how to understand this topic, I think this should be not as good as they answer, because many people don’t really understand the virtual DOM its value, I this article from the birth of the virtual DOM to introduce its value and historical status, process and help you understand it.

What is the virtual DOM

Essentially a JavaScript object, this object is a more lightweight description of the DOM.

Yes, it’s that simple!

It’s just a complicated object, there’s nothing to talk about, but why it’s there, and what are the benefits of having this description is what we’re going to talk about today.

Why the virtual DOM

Before we talk about why we use the virtual DOM, let’s talk about how React was born. After all, if we know the historical background and think about its birth, we know that it was inevitable.

After checking many historical articles about React, I found this article worthy of convincing me: How React was refined.

It’s no secret that Facebook is big on PHP, so React was inspired by PHP.

String Concatenation era – 2004

At this point in 2004, everyone was still developing websites using PHP string concatenation:

$str = '<ul>';
foreach ($talks as $talk) {
  $str += '<li>' . $talk->name . '</li>';
}
$str += '</ul>';
Copy the code

This way of writing code will not look good, but also prone to XSS and other security issues.

The solution is to Escape any input from the user. However, if the string is escaped multiple times, the number of unescaped times must be the same, otherwise the original content will not be retrieved. If you accidentally escape the HTML tags, the HTML tags will be displayed directly to the user, resulting in a poor user experience.

XHP Era – 2010

In 2010, Facebook developed XHP for more efficient coding while avoiding the error of escaping HTML tags. XHP is a syntactic extension of PHP that allows developers to use HTML tags directly in PHP instead of strings.

$content = <ul />;
foreach ($talks as $talk) {
  $content->appendChild(<li>{$talk->name}</li>);
}
Copy the code

This way, all HTML tags use a different syntax than PHP, and we can easily tell which ones need to be escaped and which ones don’t.

It wasn’t long before Facebook engineers realized that they could create custom tags, too, and that combining custom tags could help build large applications.

JSX – 2013

In 2013, front-end engineer Jordan Walke presented his manager with a bold idea: migrate XHP extensions to JS. The first thing you need is an extension to enable JS to support XML syntax, called JSX. JSX was implemented very quickly because Node.js was already in a lot of practice on Facebook.

You can guess why you want to migrate to JS, but I guess it’s because of the separation of the front and back ends.

const content = (
  <TalkList>
    { talks.map(talk => <Talk talk={talk} />)}
  </TalkList>
);
Copy the code

React

At this point, another tricky problem is that you need to manipulate the DOM during updates. Traditional DOM apis are so detailed and complex that they are prone to bugs and the code is difficult to maintain.

Then I came up with the update mechanism of the PHP era, where every time something changes, you just jump to a new page rendered by PHP.

From a developer’s point of view, it’s very easy to develop your app this way because you don’t have to worry about changes and everything is synchronized when user data changes on the interface.

React came up with the idea of always “refreshing” the page as a whole

React automatically updates the UI when state changes back and forth, freeing us from complex UI operations and allowing us to only worry about state and what the final UI will look like.

Let’s look at the difference between a partial refresh and a global refresh.

The picture is from Geek Time teacher Wang Pei’s React Advance and Combat.

Partial refresh:

// Here is the pseudo-code
var ul = find(ul) // find ul first
ul.append(`<li>${message3}</li>`) // Then insert message3 to the end

// Think of the NTH in the middle instead of the last
var ul = find(ul) // find ul first
var preli = find(li(n- 1)) // Find a li of n-1
preli.next(`<li>${message3}</li>`) // Insert after n-1
Copy the code

Overall refresh:

UI = f(messages) // Refresh all 3 messages, just call f

// This is defined during the initial rendering, so it is not needed during the update
function f(messages) {
	return <ul>
		{messages.map(message => <li>{ message }</li>)}
	</ul>
}
Copy the code

At this point, I just need to relate my state (what the data is) and what the UI looks like (layout), no more relational manipulation details.

Although this method is simple and crude, the obvious disadvantage is that it is very slow.

Another problem is that the state of the node cannot be included in this way. For example, it loses the currently focused element and cursor, as well as the text selection and page scroll position, which are the current state of the page.

Diff

To solve the above problem, leave the UNCHANGED DOM nodes as they are, and only create and replace the DOM nodes that have been changed. This method implements DOM node Reuse.

At this point, you can update the DOM as long as you can identify which nodes have changed. The problem then becomes how to compare the differences between the two DOM’s.

Speaking of contrasting differences, it’s probably easy to think of version control (Git).

DOM is a tree structure, so diff algorithm must be for tree structure. At present, the known diff algorithm of complete tree structure is O(n^3).

Complete Tree Diff implementation algorithm.

But the time complexity O(n^3) was too high, so Facebook engineers took into account the special case of the component and reduced it to O(n).

React diff

Virtual DOM

As mentioned earlier, React actually implements version control of DOM nodes.

As anyone who has done JS application optimization probably knows, DOM is complex and manipulating it (especially queries and creation) can be very slow and costly. Look at the example below. Just create a blank div and you have 231 example attributes.

// Chrome v63
const div = document.createElement('div');
let m = 0;
for (let k in div) {
  m++;
}
console.log(m); / / 231
Copy the code

With so many DOM attributes, most of them are useless for Diff, so you can avoid a lot of DOM queries by replacing complex DOM nodes with lighter JS objects and moving the DOM Diff operations to JS objects. This lighter JS object is called the Virtual DOM.

So here’s the process:

  1. Maintain a Virtual DOM represented by JS objects that correspond to the real DOM
  2. Diff the first and second Virtual DOM and generate the Mutation.
  3. Apply the changes to the real DOM to generate the latest real DOM

As you can see, since changes are applied to the real DOM, you still have to manipulate the DOM directly, but the React diff algorithm minimizes DOM changes.

The rest of history has already led to the main point of this article: the virtual DOM. The detailed history shows how React was developed, and there are many excerpts from the historical part of the article.

conclusion

Traditional front-end programming is imperative, manipulating the DOM directly and telling the browser what to do. The problem is that a lot of code is used to manipulate DOM elements, and the code is not readable or maintainable.

React changed the imperative to declarative, abandoning the details of direct DOM manipulation and focusing only on data changes. DOM manipulation was done by the framework, which greatly improved the readability and maintainability of code.

Early on, we can see that data changes cause the entire page to be refreshed, which is inefficient because it may be a local data change, but refreshing the entire page is unnecessary overhead.

Therefore, there is a Diff process, which compares the DOM structure before and after data changes, finds out the differences between the two, and then updates and renders the differences.

But because the entire DOM structure is too large, a more lightweight description of the DOM is adopted – the virtual DOM.

However, it should be noted that the emergence of virtual DOM and Diff algorithms is to solve the performance problems caused by the transformation from imperative programming to declarative programming and data-driven programming. In other words, the performance of direct DOM manipulation is no worse than the virtual DOM and Diff algorithms, and even better.

The reason for this is because of the Diff algorithm’s comparison process, which is to find different and therefore targeted updated pages. But comparisons also cost performance. Manipulating the DOM directly is targeted, and we know what to update and what not to update, so we don’t need to compare. So it might be more efficient to manipulate the DOM directly.

The smart thing about React isn’t that it’s faster than DOM, but that no matter how your data changes, I can update the DOM with minimal cost. The way I do this is I refresh a virtual DOM tree in memory with the new data, compare the old and new ONES, find the differences, and update them to the DOM tree.

The point of a framework is to mask the underlying DOM manipulation for you and make your code more maintainable by allowing you to describe your purpose in a more declarative way. No framework can be faster than purely manual DOM optimization, because the framework’s DOM manipulation layer needs to handle any operations that the upper API might produce, and its implementation must be universal.

If you want to know more about the relationship between virtual DOM and performance, please check out the following two articles and the zhihu topic in the public account to give you a deeper understanding of the virtual DOM.

  • Stop talking about virtual DOM. You’re gonna get punched in the face
  • Dig deep into the virtual DOM, and it’s really unpleasant
  • React is faster than the REAL DOM

As another point, many people associate Diff with data updates and performance improvements, but consider this: React only triggers updates and doesn’t know the exact data changes, so Diff is needed to find differences and patch difference queues. Vue uses the method of data hijacking to accurately get the changing data, why use the virtual DOM?

The role of the virtual DOM

To answer that question, don’t just think of virtual DOM or React as a performance solution. Here I summarize some of the benefits of the virtual DOM.

  • Virtual DOM adds maintainability at the expense of (critically) some performance, which is common to many frameworks.
  • Centralized operation of DOM is realized. When data is changed, the virtual DOM is modified first, and then reflected into the real DOM. DOM is updated with the lowest cost to improve efficiency (to improve efficiency, think about which stage compared with the improved efficiency, do not only remember this one).
  • Opens the door to functional UI programming.
  • Can render outside of the DOM, making frameworks cross-platform, such as ReactNative, React VR, etc.
  • Can better achieve SSR, isomorphic rendering. This one is actually the same as the one above.
  • High abstraction of components.

Given that the virtual DOM has so many uses, what is the reason for Vue’s adoption of the virtual DOM?

The main reason Vue 2.0 introduced VDOM was that it abstracted the rendering process, making components more abstract and adaptable to rendering targets outside the DOM. Uvu article: Vue’s philosophy problem

Disadvantages of the virtual DOM

  • When rendering a large number of DOM for the first time, it is slower than innerHTML insertion due to the extra layer of virtual DOM computation.
  • The virtual DOM requires that a copy of the DOM be maintained in memory (the above one is similar, for speed, this one for space).
  • This is appropriate if the virtual DOM changes a lot. But with a single, frequent update, the virtual DOM will take more time to compute. So, if you have a page with relatively few DOM nodes, using the virtual DOM, it might actually be slower. But for most single-page applications, this should be faster.

conclusion

This article introduces the virtual DOM and does not explain its implementation and related Diff algorithm like other articles. About the Diff algorithm, you can see what is the virtual DOM in this article? The React diff algorithm is not too fast.

But through history to get his value reflected, from the history of how the great people to solve the problem step by step, from the history of why others can make such great things, but we can not?

Every great product has a lot of background support and is developed step by step.

It also eliminates the misconception that the biggest advantage of the virtual DOM is the diff algorithm, which reduces the performance cost of JavaScript manipulating the real DOM.

While this virtual DOM brings one advantage, it’s not the whole story. The biggest advantage of the virtual DOM is that it abstracts the original rendering process and achieves cross-platform capabilities, rather than being limited to the BROWSER DOM. It can be a native component of Android and IOS, a popular small program recently, or a variety of GUIs.

Finally, I hope we think more and follow the tide to stand on the top of the tide.

Refer to the link

  • Why and performance issues with the virtual DOM?
  • How did React come into being

Afterword.

I am taoweng, a thinking front-end ER, want to know about more front-end related, please pay attention to my public number: “front-end Taoyuan”, if you want to join the exchange group to follow the public number of “wechat” to pull you into the group