为何Vue3不使用时间切片(Time Slicing)

翻译自Vuejs issue中尤大的回答:原文地址vue

在Web应用程序中,丢帧(janky)更新一般是因为同步的高CPU时间和原生DOM的更新形成的。git

时间切片是在CPU工做期间保持应用响应的一种尝试,但它只影响CPU工做。DOM的刷新必须是同步的,以确保最终DOM状态的一致性。github

因此,想象两种丢帧更新的场景:数组

  1. CPU工做时间在16ms之内,可是须要操做大量的原生DOM更新操做(例如,挂在大量新的DOM内容)。无论你有没有使用时间切片,应用依旧会感受到掉帧。
  2. CPU任务很是繁重,须要超过16ms的时间。从理论上讲,时间切片开始发挥做用了。然而,HCI的研究代表,除非它在进行动画,不然对于正常的用户交互,大多数人对于100毫秒内的更新是感受不到有什么不一样的。

也就是说,只有在频繁进行超过100ms的纯CPU任务更新时,时间切片才实际有用。缓存

有趣的地方在于,这样的场景更常常地发生在React中,由于:markdown

  1. React的虚拟DOM操做(reconciliation )天生就比较慢,由于它使用了大量的Fiber架构;架构

  2. React使用JSX来渲染函数相对较于用模板来渲染更加难以优化,模板更易于静态分析。并发

  3. React Hooks将大部分组件树级优化(即防止没必要要的子组件的从新渲染)留给了开发人员,开发人员在大多数状况下须要显式地使用useMemo。并且,无论何时React接收到了children属性,它几乎总要从新渲染,由于每次的子组件都是一棵新的vdom树。这意味着,一个使用Hook的React应用在默认配置下会过分渲染。更糟糕的是,像useMomo这类优化不能轻易地自动应用,由于:框架

    1. 它须要正确的deps数组;
    2. 盲目地任意使用它可能会阻塞本该进行的更新,相似与PureComponent

    不幸的是,大多数开发人员都很懒,不会积极地优化他们的应用。因此大多数使用Hook的React应用会作不少没必要要的CPU工做。dom

相比之下,Vue就上面的问题作一下比较:

  1. 本质上更简单,所以虚拟DOM操做更快(没有时间切片-> 没有fiber-> 更少的开销);

  2. 经过分析模板进行了大量的AOT优化,减小了虚拟DOM操做的基本开销。Benchmark显示,对于一个典型的DOM代码块来讲,动态与静态内容的比例大约是1:4,Vue3的原生执行速度甚至比Svelte更快,在CPU上花费的时间不到React的1/10。

  3. 智能组件树级优化经过响应式跟踪,将插槽编译成函数(避免子元素重复渲染)和自动缓存内联句柄(避免内联函数重复渲染)。除非必要,不然子组件永远不须要从新渲染。这一切不须要开发人员进行任何手动优化。

    这意味着对于同一个更新,React应用可能形成多个组件从新渲染,但在Vue中大部分状况下只会致使一个组件从新渲染。

默认状况下, Vue3应用比React应用花费更少的CPU工做时间, 而且CPU工做时间超过100ms的机会大幅度减小了,除非在一些极端的状况下,DOM可能成为更主要的瓶颈。

如今,时间切片或并发模式带来了另外一个问题:由于框架如今安排和协调了全部更新,它在优先级、失效、从新实例化等方面产生了大量额外的复杂性。全部这些逻辑处理都不可能被tree-shaken,这将致使运行时基线的大小膨胀。即便包含了Suspense和全部的tree-shaken,Vue 3的运行时仍然只有当前React + React DOM的1/4大小。

注意,这并非说并发模式是一个很差的主意。它提供一个有趣的新方法解决某一类问题(尤为是相关协调异步状态转换),但时间切片(做为并发的一个子特性)特别解决了React中比其余框架更突出的问题,同时也带来了成本。对于Vue 3来讲,这种权衡彷佛是不值得的。

相关文章
相关标签/搜索