🎉尤雨溪为什么要推出Vapor Mode🎉

77,005 阅读2分钟

文章首发公众号:萌萌哒草头将军

演示源码和在线演示地址,公众号回复”演示“获得

🚀Svelte原理和进阶看这篇就够了🚀

学不完的框架,🐔啄不完的米,SolidJS,你到底爱谁?😘

🎉SolidJS响应式原理和简易实现🎉

🎉Vue3优雅的监听localStorage变化🎉

Vapor Mode是尤雨溪在2022 Year In Review给定相中提出的概念,本篇文章我们将直观感受下尤雨溪为啥要推出Vapor Mode

🎉前端开发书籍推荐

💎前情提要

在前面两篇文章中反复提到了不同框架编译之后的差异

  • 🚀 React编译之后是Jsx函数返回的虚拟DOM
  • 🚀 Vue编译之后是render函数返回的虚拟DOM
  • 🚀 SolidJS编译之后返回的真实DOM字符串
  • 🚀 Svelte编译之后返回的是真实DOM片段

React由于架构机制决定了每当状态发生改变,从当前组件开始一直到叶子组件重新加载。

Vue由于给每个组件建立了watchEffect监听机制,每当组件依赖的状态发生改变,当前组件重新加载。

SolidJSSvelte由于在编译之后就确定了当状态发生改变UI随之变化的关系,所以仅仅是具体DOM的重新加载。

根据这些不同的更新粗细粒度,他们被分为

粒度成员
粗粒度React
中粒度Vue
细粒度SolidJSSvelte

💎直观感受

为了直观感受更新时的区别,现在我们设计如下关系的组件:

    GrandFatherFather
      |
    Child

每个组件的背景色都是随机的,并且在Father组件中,实现了一个Count功能。

我们用四个框架分别实现。下面只给出一个例子。

生成随机颜色:

`#${(~~(Math.random()*(1<<24))).toString(16)}`

Father组件如下:

// Father.jsx
import React, { useState } from 'react'

const Father = () => {

  const [count, setCount] = useState(0)

  const onClick = () => setCount(count => count ++)

  return (
    <div style={{ display: "flex" }}>
      <div
        onClick={() => onClick()}
        style={{
          height: 100,
          width: `40vw`,
          background: `#${(~~(Math.random() * (1 << 24))).toString(16)}`,
        }}
      >
        {count}
        <Child />
      </div>
      <div
        onClick={() => onClick()}
        style={{
          height: 100,
          width: `40vw`,
          background: `#${(~~(Math.random() * (1 << 24))).toString(16)}`,
        }}
      ></div>
    </div>
  )
}

export default Father

接下来,我们看看他们在触发onClick时的不同表现吧。

🚀 React

2023-05-26 18.10.14.gif

🚀 Vue

2023-05-26 18.09.46.gif

🚀 Svelte

2023-05-26 18.42.51.gif

🚀 SolidJS

2023-05-26 18.10.36.gif

🚀 结论

上面的图中,可以直观的看到:

React在当前组件状态发生变化时,从当前组件开始,包括子组件都被重新加载了。

Vue仅仅是当前组件重新加载。

SolidJSSvelte仅仅是重新加载对应的DOM

💎总结

在项目比较小时,SolidJSSvelte的优势不会很明显,

但是当面对大型项目时,ReactVue的性能短板就显露出来了。

面对这样的压力,尤雨溪在年初的展望里已经预告了Vapor mode,该模式的灵感就是受到了SolidJS的启发。

它可以在给定相同的Vue SFC前提下,与当前基于虚拟DOM的输出相比,Vapor Mode将其编译成性能更高、使用更少内存且需要更少运行时支持代码的JavaScript输出。

对于React由于架构机制的限制,目前很难做出根本性的改变,

对于开发者,我们可以选择手动优化。例如,将组件使用memo包裹起来。

const Child = memo(() => <Comp>your comp</Comp>)

此时上面的例子中,React的效果更新效果就和Vue类似了。 2023-05-26 18.09.46.gif

我们为了演示每次dom都是重新加载的,所以样式是直接这样写的。

background: `#${(~~(Math.random() * (1 << 24))).toString(16)}`

在实际开发中,要尽量避免无意义的重复计算,尤其React中,比如:

// bad
<Comp
  style={
    margin: window.screen.width / 3 * 2
  }
/>

// good
const App = () => {
  const margin = useMemo(() => window.screen.width / 3 * 2, [])
  return <Comp style={ margin } />
}

// bettter
const margin = window.screen.width / 3 * 2

const App = () => {
  return <Comp style={ margin } />
}

好了今天的分享就到这了,文章中如果出现问题,有劳各位大佬指正!