最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Virtual DOM 简直就是挥霍

    正文概述 掘金(前端子鱼)   2021-02-27   618

    注意:原文发表于2018-12-27,随着框架不断演进,部分内容可能已不适用。

    近年来,如果你有使用过 JavaScript 框架,那么你可能听说过“Virtual DOM 飞快”,甚至认为比真实的 DOM 还要快。

    令人震惊的是,这种说法竟然深入人心。

    有人曾问我 Svelte 不使用 Virtual DOM,它为何更快?看来现在是时候仔细探讨一下。

    什么是 Virtual DOM?

    在众多框架中,你通常是使用 render() 函数来构建应用程序UI的,就像下方这个简单的 React 组件:

    function HelloMessage(props) {
      return (
        <div className="greeting">
          Hello {props.name}
        </div>
      );
    }
    

    不用 JSX,你一样可以做同样的事情……

    function HelloMessage(props) {
      return React.createElement(
        'div',
        { className: 'greeting' },
        'Hello ',
        props.name
      );
    }
    

    ……后者正是前者的宗本道源,其结果自然一致:代表的是页面渲染的对象。

    这个对象就是 Virtual DOM。

    一旦程序更新了状态(例如 name 属性被修改),便会创建新的对象。

    框架要做的工作是对比新旧对象之间的差异,找出需要进行重新渲染的部分,并将其应用到真实的 DOM 中。

    这种观念是如何开始的?

    关于 Virtual DOM 性能的误解,可以追溯到 React 正式发布那会。

    在2013年,React 前团队核心成员 Pete Hunt 在《重新思考最佳实践》的演讲中提到:

    Virtual DOM 简直就是挥霍

    截图来自 JSConf EU 2013 《重新思考最佳实践》

    但是 —— 慢着!

    Virtual DOM 只是真实 DOM 操作锦上添花的补充而已。

    它之所以快,是因为拿性能更差的框架做对比(在2013年,可以欺负的选择有很多!),另一种选择是做一些他人不屑去做的事情:

    onEveryStateChange(() => {
      document.body.innerHTML = renderMyApp();
    });
    

    Pete 很快就澄清……

    …… 但这还是没有挠到痒处。

    那么……Virtual DOM 慢吗?

    并不尽然。

    如果能够防患于未然,那确实“Virtual DOM 飞快”。

    React 最初的承诺是,你可以在每次状态改变时,自动重新渲染你的整个应用,且不用担心性能。

    不敢苟同。

    果真如此,那就不需要像 shouldComponentUpdate 这样的优化了(这是一个用于告诉 React 何时可以安全地跳过一个组件的方法)。

    就算用了 shouldComponentUpdate,一次性更新整个应用的 Virtual DOM 也大费周折。

    前不久 React 团队引入一种叫 React Fiber 的东西,它可以将更新划分成较小的块。

    这意味着(除了其他事项外)更新不会长时间阻塞主线程,尽管它不会减少工作总量或总体耗时。

    开销从何而来?

    显而易见,DOM差异比较(diffing)并非毫无代价。

    这必须先将新的 Virtual DOM 与旧的差异(快照)进行比较,然后才能对真实 DOM 应用更改。

    就拿前面的 HelloMessage 为例,假设 name 属性从“world”更改为“everybody”:

    1. 两个快照都包含一个元素,在这种情况下,它都是 <div>,这意味着我们可以保持相同的 DOM 节点。

    2. 我们枚举 <div> 旧的和新的所有属性,以查看是否需要更改、添加或者删除任何属性。在这两种情况下,我们都有一个特性,就是它的值为“greeting”的类名

    3. 扫描元素内部,我们看到文本已经更改了,因此我们需要更新实际的 DOM。

    在上述三步里,只有第3步在该示例中有价值,因为程序的基本结构是没有改变的,这其实在绝大多数的更新中都是如此。

    如果我们直接跳到第3步,效率就高得多了:

    if (changed.name) {
      text.data = name;
    }
    

    (这几乎就是 Svelte 生成的更新代码了。与传统的 UI 框架有所不同,Svelte 是一个编译器,它可以在构建时便知悉程序中可能发生的变化,而非运行时。)

    不止差异比较一个方面

    React 和其他 Virtual DOM 框架使用的 diffing 算法速度都很快。

    换而言之,组件本身的开销更大。

    例如你不太可能会写出这样的代码……

    function StrawManComponent(props) {
      const value = expensivelyCalculateValue(props.foo);
    
      return (
        <p>the value is {value}</p>
      );
    }
    

    如果这么干,无论 props.foo 是否已经更改,你可能会粗心地在每次更新时不小心重新计算了 value

    不过,对于进行不必要的计算和分配,更普遍的是下面这种方式:

    function MoreRealisticComponent(props) {
      const [selected, setSelected] = useState(null);
    
      return (
        <div>
          <p>Selected {selected ? selected.name : 'nothing'}</p>
    
          <ul>
            {props.items.map(item =>
              <li>
                <button onClick={() => setSelected(item)}>
                  {item.name}
                </button>
              </li>
            )}
          </ul>
        </div>
      );
    }
    

    在这里,我们每次状态更改时,都要生成一个新的虚拟的 <li> 元素数组,每个元素都有自己内联的事件处理程序,而不论 props.items 是否发生了变化。

    除非你对性能有所不满,否则就不会对其进行优化。这么干毫无意义,它足够快了。

    但是你想知道怎样会更快吗?那是在浪费时间。

    其实,默认就做一些不必要的计算(即使是微不足道的),其危险之处在于你的应用最终会温水煮青蛙般死掉,因为没有明显的瓶颈值得去优化。

    React Hooks 会使情况变本加厉,结果可想而知。

    Svelte 专门设计用来防止你陷入这种困境。

    那些框架为何还要用 Virtual DOM?

    关键是要理解:Virtual DOM 不是一种特性,而是一种手段。

    它要达到的目的是支持声明式的、状态驱动的 UI 开发。

    Virtual DOM 很有价值,因为它允许你在构建应用程序时无需考虑状态转换,而且性能通常_已经足够好了_。

    这意味着更少的错误代码,更多的时间花在创造性的任务上,而不是在单调乏味的地方折腾。

    但事实证明,我们可以在不使用 Virtual DOM 的情况下实现类似的编程模型 —— 这正是 Svelte 的用武之地。

    < The End >

    - 窗明几净,静候时日变迁 -


    起源地下载网 » Virtual DOM 简直就是挥霍

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元