React设计原理-前端框架原理概览

249 阅读4分钟

初识前端框架

UI = f(state), 其中state代表当前视图状态, f代表框架内部运行机制, UI代表宿主环境的视图. 即“框架内部运行机制根据当前状态渲染视图”

如何描述UI

现在有两种主流的“方案”: jsx模板语言, 两者都可以描述UI逻辑. 模板语言UI出发, 扩展UI, 描述逻辑(如早前的PHP模板语法); jsx从逻辑出发, 扩展逻辑, 描述UI(类XHML语法的ES语法糖).

如何组织UI与逻辑

组件: 一种存放UI和逻辑的松散耦合单元. 逻辑中的变量改变最终会影响UI变化. 另外组件的自变量或因变量传递给另外一个组件, 作为其自变量, 即props. 同时也可以通过store跨层级传递.

// react
// 自变量x
const [x, setX] = useState(0);
console.log(x)
setX(2)
// 因变量y
const y = useMemo(() => x*3 + 1, [x])
console.log(x)

// vue
// 自变量x
const x = ref(0)
console.log(x.value)
x.value = 2
// 因变量y
const y = computed(() => x*3 + 1)
console.log(y.value)

前端框架使用的技术

细粒度更新

vueMobx中使用的“自动追踪依赖的技术”被称为“细粒度更新”.

// react 中需要显示指明因变量依赖的自变量 
const y = useMemo(() => x*3 + 1, [x])
// vue
const y = computed(() => x*3 + 1)
// Mobx
const y = computed(() => x*3 + 1)

y本质是一个getter函数, 访问时可以趁机建立effect(对callback进行了包装)与x的订阅发布关系并收集依赖(便于清除). 当x变化时通知订阅变化的effect函数执行(清除并重新收集依赖), 即因变量y跟随变化.

AOT

编译可以选择两个时机执行:

  1. 代码在构建时(AOT-AHead of time, 提前编译或预编译), 宿主环境获取的是编译后的代码.
  2. 代码在宿主环境中编译并执行(JIT-just in time, 即时编译).

前端框架可以从AOT中受益, 减少“根据自变量变化计算出UI变化”的工作量. 而“采用JSX描述UI”难以从AOT获益, 因为ES语法的灵活难以进行静态分析.

Vritual DOM

虚拟dom的优点有: 1. 相较于dom的体积优势; 2. 相较于AOT更强大的描述能力; 3. 多平台渲染的抽象能力.

vue使用模板描述UI, 模板编译为render函数的执行结果就是vnode, 与之前的版本进行patch计算出UI中变化的部分.

react使用jsx描述UI, jsx编译为createElement方法, 执行结果是“react element描述的ui”, 与之前“FiberNode描述的ui”进行比较计算出UI中变化的部分, 同时生成本次更新“FiberNode描述的ui”.

前端框架的实现原理

Svelte

Svelte是一款重度依赖AOT的元素级框架. 借由模板语法的约束, 经过AOT的编译优化, Svelte可以直接建立“自变量与元素的对应关系”. 在运行时省略了“根据自变量变化计算出UI变化”这一步骤, 使其在执行“细粒度更新”时比“使用VDOM的框架”的整体更新路径更短.

svelte.png

vue3

watchEffect依赖的自变量变化时, 调用render函数生成VNode并与之前的版本进行比较(patch)最终执行对应的DOM操作完成更新. 且在AOT中收集动态可变的节点存入dynamicChildren, 减少运行时需要对比的节点数量而受益. vue.png

React

  1. 触发事件, 改变自变量并开启更新流程
  2. 执行VDOM相关操作, 即reconcile
  3. 根据2计算出的“需要变化的UI”执行对应的UI操作, 即commit react.png

React每次更新流程都是从应用的根节点开始遍历整个应用, 甚至不需要确定哪个变量发生了变化. 由于任何自变量的变化都会开启一次遍历应用的更新流程, 因此React不需要“细粒度更新”和AOT. 基于“重运行时”架构, React拓展了许多能力:

  1. 优先级调度
  2. Time Slice
  3. Hooks
  4. Suspense

总结

  • Svelte是极致的编译时框架
  • React是极致的运行时框架
  • Vue3同时拥有两者的特性(AOT和VDOM), 比较均衡.
  • 用于在运行时建立“自变量与因变量关系”的“细粒度更新”.
  • 用于在编译时建立“自变量与因变量关系”的AOT.
  • 用于在运行时实现“根据自变量变化计算出UI变化”的VDOM.