Open li-jia-nan opened 1 year ago
前段时间,StackOverflow发布了2021调查报告,Svelte作为一个非主流框架,技压React、Vue等众多前端框架,成为了web领域最受欢迎的框架,你听说过Svelte吗?
Svelte
React
Vue
从React15到17,再到即将到来的React18,再从Vue2到Vue3,会不会有种前端框架发展太快?学不动了的感觉?
那么我们来探讨一下,这些主流框架之间的区别吧
tips:本文借鉴了卡颂老师在B站发布的视频,本文发布已征得本人同意,点击查看原视频:『货很干』主流前端框架的实现原理,懂完了你
主流前端框架都遵循组件化的开发模式,具体来说,框架开发的应用分为三级抽象:
应用 => 组件 => 节点
就拿掘金App举例来说,掘金是一个应用,这个应用由header组件、导航栏组件、列表组件、footer组件四个部分构成,而这些组件还能继续拆分,比如列表组件由多个列表项组件构成,导航栏组件由多个导航组件构成,导航组件内部,由描述视图的节点加上业务逻辑构成。
header组件
导航栏组件
列表组件
footer组件
列表项组件
导航组件
节点
业务逻辑
<ul>
<li>
总结一下:框架中最小的单位是节点,节点加业务逻辑构成组件,多个组件构成应用,这就是前端框架的抽象层级划分。
那么前端框架的工作原理是什么呢?我们可以用一个公式概括:UI = F(state)
UI = F(state)
总结起来就是:框架内部的运行机制根据状态渲染视图
运行机制
状态
视图
说到这里大家可能会有疑惑,既然主流前端框架的工作原理都是一样的,那它们有什么区别呢?
答案是:更新粒度的区别
刚才讲过,框架有三级抽象:应用、组件、节点,同样的,主流前端框架也分为三种更新粒度,应用级,组件级,节点级,接下来我们看看这些框架内部都由哪些技术构成:
应用
组件
应用级
组件级
节点级
我们从最细的粒度,节点级更新的框架Svelte开始讲起(如果想了解这个框架,可以点击这里查看官网)
首先定义一个计数器组件,先定义组件逻辑:
count
handleClick
<button>
<p>
经过渲染,视图上的数字初始值为0,每次点击都会加1
状态变化
节点变化
具体方法
对应视图
在我们上面的例子中:
变量count变化可能导致<button>节点中的文本节点发生变化,由于<p>节点不包含状态变化,所以它不会出现在编译后的update方法中(这种将状态变化可能导致的节点变化编译为具体方法的技术,被称为预编译,网站中实际运行的代码,都是预编译之后的代码)
预编译
监听状态变化,具体方案是采用了发布订阅设计模式,当创建一个状态后,会为状态维护一张订阅了该状态变化的表,所有需要监听变化的回调函数都在表中进行了注册,这就是发布订阅中的订阅部分
发布订阅
订阅了该状态变化
监听变化
注册
订阅
每当状态变化,会发布这张表,将状态变了这一消息发布出去,每个订阅该状态变化的回调函数都会收到通知并执行,这就是发布订阅中发布的部分
发布
状态变了
订阅该状态变化的回调函数
通过以上这种方式,框架能对每个状态化做出反应,这种精确到状态的更新被称为细粒度更新,这也就是节点级更新框架的工作原理。
细粒度更新
讨论到应用级更新框架,这种框架会采用虚拟DOM的技术,我们通过 React 来举例,首先,我们用 React 重写刚才的 Counter 组件:
import React, { useState } from 'react'; const Counter: React.FC = () => { const [count, setCount] = useState<number>(0); const handleClick = () => setCount(count + 1); return <button onClick={handleClick}>{count}</button>; }; export default () => ( <> <Counter /> <Counter /> </> );
在父组件内使用两个 <Counter /> 子组件,这两个 Counter 子组件可以独立计数
<Counter />
首屏渲染时,React会根据应用的树结构,生成一颗对应的虚拟DOM树
虚拟DOM树
每个节点
同级节点
button
虚拟DOM
刚才讲过,节点级更新的框架需要监听状态的变化,与节点级框架不同,应用级框架不关心是哪个状态发生了变化,应用中的任何组件中的任何一个状态变化,都会从root根节点创建一颗完整的虚拟DOM树,然后通过前后两棵虚拟DOM树的比较,找到变化的部分,最终将变化的部分更新到视图,主流的应用级更新框架就是React
根节点
你可能会问:为什么状态变化后,要生成一颗完整的虚拟DOM树,而不是只为改变的状态对应的组件生成对应的虚拟DOM树?这样一来,就能节省很多虚拟DOM操作的开销,从而降低内存的开销,达到性能优化的目的
完整的虚拟DOM树
对应的组件
对应的虚拟DOM树
作为组件级更新框架的代表,Vue2采用虚拟DOM + 细粒度更新实现,Vue3则在此基础上引入了预编译,并升级了细粒度更新的实现。
最后总结一下:主流前端框架的工作原理是 框架的运行机制根据状态渲染视图,他们的区别是更新粒度不同,三种更新粒度的框架分别对应不同的技术点:
前言
前段时间,StackOverflow发布了2021调查报告,
Svelte
作为一个非主流框架,技压React
、Vue
等众多前端框架,成为了web领域最受欢迎的框架,你听说过Svelte
吗?从React15到17,再到即将到来的React18,再从Vue2到Vue3,会不会有种前端框架发展太快?学不动了的感觉?
那么我们来探讨一下,这些主流框架之间的区别吧
tips:本文借鉴了卡颂老师在B站发布的视频,本文发布已征得本人同意,点击查看原视频:『货很干』主流前端框架的实现原理,懂完了你
组件化
主流前端框架都遵循组件化的开发模式,具体来说,框架开发的应用分为三级抽象:
应用 => 组件 => 节点
就拿掘金App举例来说,掘金是一个应用,这个应用由
header组件
、导航栏组件
、列表组件
、footer组件
四个部分构成,而这些组件还能继续拆分,比如列表组件
由多个列表项组件
构成,导航栏组件
由多个导航组件
构成,导航组件内部,由描述视图的节点
加上业务逻辑
构成。<ul>
标签包裹的<li>
节点<li>
节点时,需要跳转到对应的地方,并且更新列表组件
中的数据总结一下:框架中最小的单位是节点,节点加业务逻辑构成组件,多个组件构成应用,这就是前端框架的抽象层级划分。
那么前端框架的工作原理是什么呢?我们可以用一个公式概括:
UI = F(state)
总结起来就是:框架内部的
运行机制
根据状态
渲染视图
说到这里大家可能会有疑惑,既然主流前端框架的工作原理都是一样的,那它们有什么区别呢?
答案是:更新粒度的区别
刚才讲过,框架有三级抽象:
应用
、组件
、节点
,同样的,主流前端框架也分为三种更新粒度,应用级
,组件级
,节点级
,接下来我们看看这些框架内部都由哪些技术构成:节点级更新框架:Svelte
我们从最细的粒度,节点级更新的框架Svelte开始讲起(如果想了解这个框架,可以点击这里查看官网)
首先定义一个计数器组件,先定义组件逻辑:
count
,初始值为0handleClick
,每次点击时count + 1<button>
节点,将点击事件绑定为<button>
节点的点击回调函数<p>
节点,内容为一段文本经过渲染,视图上的数字初始值为0,每次点击都会加1
节点级更新框架的原理分为三步:
状态变化
可能导致的节点变化
编译为具体方法
状态变化
状态变化
后,直接调用具体方法,改变对应视图
在我们上面的例子中:
变量
count
变化可能导致<button>
节点中的文本节点发生变化,由于<p>
节点不包含状态变化,所以它不会出现在编译后的update方法中(这种将状态变化可能导致的节点变化编译为具体方法的技术,被称为预编译
,网站中实际运行的代码,都是预编译
之后的代码)监听状态变化,具体方案是采用了
发布订阅
设计模式,当创建一个状态后,会为状态维护一张订阅了该状态变化
的表,所有需要监听变化
的回调函数都在表中进行了注册
,这就是发布订阅中的订阅
部分每当状态变化,会
发布
这张表,将状态变了
这一消息发布出去,每个订阅该状态变化的回调函数
都会收到通知并执行,这就是发布订阅中发布
的部分通过以上这种方式,框架能对每个状态化做出反应,这种精确到状态的更新被称为
细粒度更新
,这也就是节点级更新框架的工作原理。应用级更新框架:React
讨论到应用级更新框架,这种框架会采用虚拟DOM的技术,我们通过
React
来举例,首先,我们用 React 重写刚才的 Counter 组件:在父组件内使用两个
<Counter />
子组件,这两个 Counter 子组件可以独立计数首屏渲染时,React会根据应用的树结构,生成一颗对应的
虚拟DOM树
<button>
节点后,调用handleClick
,触发状态更新,react会重新生成一颗完整的虚拟DOM树每个节点
会与之前的虚拟DOM树的同级节点
进行比较,如果存在差异,记录该差异<Counter />
组件的<button>
节点时,发现前后两个button
节点的内容不一致,就会记录下来,等新的虚拟DOM
生成完毕后,将记录的差别统一渲染到视图上总结
刚才讲过,
节点级
更新的框架需要监听状态
的变化,与节点级
框架不同,应用级
框架不关心是哪个状态发生了变化,应用中的任何组件中的任何一个状态变化,都会从root根节点
创建一颗完整的虚拟DOM树
,然后通过前后两棵虚拟DOM树
的比较,找到变化的部分,最终将变化的部分更新到视图,主流的应用级更新框架就是React
提问
你可能会问:为什么状态变化后,要生成一颗
完整的虚拟DOM树
,而不是只为改变的状态对应的组件
生成对应的虚拟DOM树
?这样一来,就能节省很多虚拟DOM操作的开销,从而降低内存的开销,达到性能优化的目的组件级更新框架:Vue
作为组件级更新框架的代表,Vue2采用虚拟DOM + 细粒度更新实现,Vue3则在此基础上引入了预编译,并升级了细粒度更新的实现。
复习一下吧
最后总结一下:主流前端框架的工作原理是 框架的
运行机制
根据状态
渲染视图
,他们的区别是更新粒度不同,三种更新粒度的框架分别对应不同的技术点: