初识前端框架
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)
前端框架使用的技术
细粒度更新
在vue和Mobx中使用的“自动追踪依赖的技术”被称为“细粒度更新”.
// 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
编译可以选择两个时机执行:
- 代码在构建时(AOT-AHead of time, 提前编译或预编译), 宿主环境获取的是编译后的代码.
- 代码在宿主环境中编译并执行(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的框架”的整体更新路径更短.
vue3
watchEffect依赖的自变量变化时, 调用render函数生成VNode并与之前的版本进行比较(patch)最终执行对应的DOM操作完成更新. 且在AOT中收集动态可变的节点存入dynamicChildren, 减少运行时需要对比的节点数量而受益.
React
- 触发事件, 改变自变量并开启更新流程
- 执行VDOM相关操作, 即
reconcile - 根据
2计算出的“需要变化的UI”执行对应的UI操作, 即commit
React每次更新流程都是从应用的根节点开始遍历整个应用, 甚至不需要确定哪个变量发生了变化. 由于任何自变量的变化都会开启一次遍历应用的更新流程, 因此React不需要“细粒度更新”和AOT.
基于“重运行时”架构, React拓展了许多能力:
- 优先级调度
- Time Slice
- Hooks
- Suspense
总结
- Svelte是极致的编译时框架
- React是极致的运行时框架
- Vue3同时拥有两者的特性(AOT和VDOM), 比较均衡.
- 用于在运行时建立“自变量与因变量关系”的“细粒度更新”.
- 用于在编译时建立“自变量与因变量关系”的AOT.
- 用于在运行时实现“根据自变量变化计算出UI变化”的VDOM.