Virtual DOM

312 阅读2分钟

一、什么是Virtual DOM

  • 一句话表示就是用 JS 对象来模拟真实的 DOM 结构, 它应该包含三个内容, 分别为标签名(tag)、属性(props)、子元素对象(children), 下面是原生 DOM 与 VDOM 对比
    <ul>
        <li><p id='demo' class='p0'>test</p></li>
    </ul>
    {
        tag: 'ul',
        props: {},
        children: [{
            tag: 'li',
            props: {},
            children: [{
                tag: 'p',
                props: {
                    id: 'demo',
                    class: 'p0'
                },
                children: ['test']
            }]
        }]
    }

二、Virtual DOM 跟原生 DOM 渲染的速度对比如何

  • 在这里我做了个实验, Mock 1000 条基础数据, 然后用 simple-virtual-dom 做为VDOM 的基础库跟原生操作 DOM 做为比较

Mock 数据
  • 测试循环添加 100 条数据, 发现使用原生的会比使用VDOM 操作要快

VDOM

原生
  • 测试循环 100 次删除所有数据,先删之后再添加所有数据, 只记录删除数据的时间, 还是原生的操作会快一点

VDOM

原生

三、为什么要使用 Virtual DOM

  • 我在知乎上找到尤大对这个问题的一些见解
  1. 原生 DOM 操作 vs. 通过框架封装操作, 这是一个性能 vs 可维护性的取舍. 框架的意义在于为你掩盖底层的 DOM 操作, 让你用更声明式的方式来描述你的目的, 从而让你的代码更容易维护
  2. 框架给你的保证是, 你在不需要手动优化的情况下, 我依然可以给你提供过得去的性能
  3. 将页面状态用 JS 对象的形式来表示, 然后配合不同的渲染工具, 实现跨平台渲染. 例如 React 使用 VDOM 实现服务端渲染(next)、浏览器渲染(react)、移动端渲染(react native)
  4. 函数式的 UI 编程方式打开了大门

四、如何实现 Virtual DOM 算法

  • VDOM 算法主要分 5 部分
  1. 构建 VDOM
    const tree = el('ul', [
      el('li', { class: 'demo' }, ['demo1']),
      el('li', { class: 'demo' }, ['demo2'])
    ]);
  1. 通过 VDOM 构建原生 DOM
    const element = tree.render();
    containerElement.appendChild(element);
  1. 生成新的 VDOM
    const newTree = el('ul', [
      el('li', { class: 'demo' }, ['demo1']),
      el('li', { class: 'demo' }, ['demo2']),
      el('li', { class: 'demo' }, ['demo3'])
    ]);
  1. 比较 VDOM 树上的差异
    const patches = diff(tree, newTree);
  1. 将差异更新到原生 DOM 上
    patch(element, patches);
  • 这是一个比较简单的例子, 在实际的运用中, 考虑的东西会更加多, 例如要处理事件监听的问题

参考资料: