前端框架原理概览
1. 前端框架原理
现代前端框架几乎都是基于描述自变量和 UI 视图之间的关系建立的,即“数据驱动视图”
前端经过长时间的发展,对于 UI 的描述语言逐渐衍生出两种解决方案
- JSX(代表框架:React):类 XML 语法的 ES 的语法糖
- 模版语法(代表框架:Vue,Svelte)
2.前端框架分类的依据
对于公式 UI = f(state) 在“自变量与因变量”理论中,state 的本质是自变量,自变量通过直接或者间接(自变量导致因变量变化)的方式来改变 UI。“被改变的 UI”仅仅是”对宿主环境 UI 的描述“,并不是实际宿主环境的 UI。
所以,**UI = f(state) **可以进一步概括为两步:- 根据自变量(state)变化来计算出 UI 的变化
- 根据 UI 的变化执行具体宿主环境的 API
- 元素级:Svelte
- 组件级:Vue
- 应用级:React
3. 细粒度更新
在 React 中定义因变量时候需要显式的指定出依赖项,而 Vue 和 Mobx 不需要
// React
const y = useMemo(() => x * 2 + 1,[x]);
// Vue
const y = computed(() => x.value * 2 + 1);
// Mobx
const y = computed(() => x.data * 2 + 1);
在 Vue 和 Mobx 中使用的“能自动追踪依赖的技术”被称为“细粒度更新”,它同时是许多前端框架剪力“自变量变化到 UI 变化”的底层原理。
4.实现 React 中的一些 Hooks
此处不管是 effect.deps 还是 state 对应的 subs 都使用了 Set 利用了集合不会重复添加数据的特性,用细粒度更新实现的 hooks 不需要去显式的指出依赖
4.1 useState
function useState(value){
// 订阅该state变化的effect
const subs = new Set();
const getter = () => {
// 获取当前上下文的effect
const effect = effectStack[effectStatck.length-1];
if(effect){
subscribe(effect,subs);
}
return value;
}
const setter = (nextValue) => {
value = nextValue;
// 通知所有订阅该state变化的effect执行
for(const effect of [...subs]){
effect.execute();
}
}
return [getter,setter];
}
function subscribe(effect,subs){
subs.add(effect);
// 依赖关系建立
effects.deps.add(subs);
}
4.2 useEffect
const [count,setCount] = useState(0);
useEffect(() => {
console.log('count is:',count());
})
setCount(2);
useEffect 实现的关键在于建立 useState 和 useEffect 之间的订阅关系
- 在 useEffect 回调中执行 useState 的 getter 时,该 Effect 会订阅该 state 的变化
- useState 的 setter 在执行时,会向所有订阅了该 state 变化的 effect 发布通知
const effect = {
// 用于执行useEffect回调函数
execute,
// 保存该useEffect依赖的state对应的subs的集合
deps: new Set()
}
function useEffect(callback){
const execute = () => {
// 重置依赖
cleanup(effect);
// 将当前effect推入栈顶
effectStack.push(effect);
try{
// 执行回调
callback();
}finally{
// effect出栈
effectStatck.pop();
}
}
const effect = {
execute,
deps: new Set();
}
execute(); // 自动收集依赖
}
function cleanup(effect){
// 从该effect订阅的所有state对应subs移除该effect
for(const subs of effect.deps){
subs.delete(effect);
}
effect.deps.clear();
}
4.3 useMemo
function useMemo(callback){
const [s,set] = useState();
// 首次执行callback后,建立回调中state的订阅发布关系
useEffect(() => set(callback()));
return s;
}
4.4 VirtualDOM(虚拟 DOM)
又称 VDOM 是目前根据自变量变化计算出 UI 变化的一种主流技术
在 Vue 中使用模版语法来描述 UI,模版语法编译为 render 函数:
- render函数执行后返回“VNode 描述的 UI”,这一步骤中 Vue 中被称为 render
- 将变化前后“VNode 描述的 UI”进行对比,计算出 UI 中变化的部分,这一部分在 Vue 中被称为 patch
React 使用 JSX 来描述 UI,JSX 编译为 createElement 方法:
- createElement 方法执行后返回“React Elemet 描述的 UI”
- “将 React Eleme 描述的 UI”与变化前“Fiber Node 描述的 UI”进行比较,计算出 UI 变化的部分,同时生成本次更新“Fiber Node 描述的 UI”
5.React 实现原理
React 被称为应用级框架的原因在于--其每次更新流程都是从应用的根结点开始,遍历整个应用。同理,Vue 起始于组件,Svelte 起始于元素。