关于 Virtual DOM 和直接 DOM 操作哪个性能更高?

2021-07-01  本文已影响0人  IllIIlIlIII

网上关于 Virtual DOM(下称VDOM) 和 直接操作 DOM 来更新页面谁的性能更高有许多争论。这里就 VDOM 的性能问题简单谈下自己的理解。

一、什么是 VDOM

VDOM 本质上是一个 Javascript 对象,用来描述 DOM 结构,如:

<html>
    <head></head>
    <body>
        <ul class="list-ul">
            <li class="list-one">List One</li>
        </ul>
    </body>
</html>

可以用如下对象表示:

const vdom = {
    tagName: "html",
    children: [
        { tagName: "head" },
        {
            tagName: "body",
            children: [
                {
                    tagName: "ul",
                    attributes: { "class": "list-ul" },
                    children: [
                        {
                            tagName: "li",
                            attributes: { "class": "list-one" },
                            textContent: "List One"
                        }
                    ]
                }
            ]
        }
    ]
}

在实际的生产环境需要将这个 JS 对象转化成真实的 DOM 元素。

二、Js 操作 DOM 的开销

1、浏览器渲染引擎工作流程大致分为如下步骤:

2、JS 频繁操 DOM 的开销:

三、为什么需要 VDOM

假如在实际生产环境中,有这么一个列表:

<ul>
    <li><span>item 1</span></li>
    <li><span>item 2</span></li>
    <li><span>item 3</span></li>
    ...
    <li><span>item 100</span></li>
</ul>

我们现在需要更新列表的,从后端拿到了数据,但是新的数据只有第50行的数据有变化。
1、最简单最节约心智的办法是,我们不关心新数据与老数据之间的差异,直接 innerHTML 更新整个 ul 标签里的内容。但是这样就造成了不必要的 DOM 操作开销,毕竟只需要更新一个节点,但是为了省事,99次操作是浪费资源的无用功。
2、或者我们逐个对比数据,发现是第50行有变化,直接将第50行的 span 用 innerText 更新内容即可。
3、虽然手动更新第50行内容达到了最小操作,但是每次从后端拿到新数据,我们并不能都知道是哪些行数据有变化,这个时候就需要写一个通用的方法来比较新旧数据的变化,并只去更新数据有变化的节点。
但是这样还不够,这个通用方法也只是满足了这一个列表的数据对比和节点更新,如果我们的项目中还有几十、几百个其它的列表呢?
这个时候 VDOM 就派上用场了。我们把整个页面抽象成 Js 对象(VDOM),每次的更新数据,我们都先更新 VDOM,再通过比较 新旧 VDOM 的变化,找到具体要更新的节点,再去操作具体的 DOM。
这个时候可能有人要问了,那在更新 VDOM 的时候不也做了很多无用功的操作吗?
对,但是 VDOM 的操作都是纯 Js 的计算,大家要明确的一点是 Js 计算(特别是在 V8 引擎的加持下)要比真实 DOM 操作开销小得多,最重要的是再也不用操心到底哪些数据有更新了,直接无脑用 VDOM 就是,开发效率提高了!

四、那到底谁的效率更高

用这个列表举例:

<ul>
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
    ...
    <li>item 100</li>
</ul>

1、当列表新数据更新了第50、60行时:

前面也说了得益于现代浏览器的高效,Js 计算是非常快的,故 T_1 + T_3 << T_2
综合比较三种更新方式,T_1 < T_1 + T_3 << T_2
可以看出手动去进行最小节点操作是性能最好的,但是其心智负担也不小。

2、当 ul 中所有数据都变了,那就能直接无脑 innerHTML 进行更新,因为此时更新所有节点就是最小节点操作。
所以一个项目能确定基本上每一页的内容都不相同,几乎要全部更新,那可以不用 VDOM,直接用 innerHTML 即可。
反之一个项目,有很多列表,有众多增删改查操作,那用 VDOM 是十分有意义的。

所以抛开场景谈性能就如同抛开剂量谈毒性,都是耍流氓。用 VDOM 更新真实 DOM 其实是在节约开销(运行效率)和节约心智(省事、提高开发效率)之间找到一个比较好的平衡点。不然为什么人家 React 和 Vue 要用 VDOM 呢?成千上万人验证过的东西,能流行一定有它的道理

上一篇 下一篇

猜你喜欢

热点阅读