likes
comments
collection
share

关于主流前端框架的本质区别

作者站长头像
站长
· 阅读数 40

前言

前段时间,StackOverflow 发布了2021 调查报告Svelte作为一个非主流框架,技压ReactVue等众多前端框架,成为了 web 领域最受欢迎的框架,你听说过Svelte吗?

关于主流前端框架的本质区别

从 React15 到 17,再到即将到来的 React18,再从 Vue2 到 Vue3,会不会有种前端框架发展太快?学不动了的感觉?

那么我们来探讨一下,这些主流框架之间的区别吧

tips:本文借鉴了卡颂老师在 B 站发布的视频,本文发布已征得本人同意,点击查看原视频:『货很干』主流前端框架的实现原理,懂完了你

组件化

主流前端框架都遵循组件化的开发模式,具体来说,框架开发的应用分为三级抽象:

应用 => 组件 => 节点

关于主流前端框架的本质区别

就拿掘金 App 举例来说,掘金是一个应用,这个应用由header组件导航栏组件列表组件footer组件四个部分构成,而这些组件还能继续拆分,比如列表组件由多个列表项组件构成,导航栏组件由多个导航组件构成,导航组件内部,由描述视图的节点加上业务逻辑构成。

  • 这里描述视图的节点可能是一个被<ul>标签包裹的<li>节点
  • 这里的业务逻辑是,当用户点击<li>节点时,需要跳转到对应的地方,并且更新列表组件中的数据

总结一下:框架中最小的单位是节点,节点加业务逻辑构成组件,多个组件构成应用,这就是前端框架的抽象层级划分。

那么前端框架的工作原理是什么呢?我们可以用一个公式概括:UI = F(state)

  • UI - 视图
  • state - 状态
  • F - 框架内部的运行机制

总结起来就是:框架内部的运行机制根据状态渲染视图

说到这里大家可能会有疑惑,既然主流前端框架的工作原理都是一样的,那它们有什么区别呢?

答案是:更新粒度的区别

刚才讲过,框架有三级抽象:应用组件节点,同样的,主流前端框架也分为三种更新粒度,应用级组件级节点级,接下来我们看看这些框架内部都由哪些技术构成:

节点级更新框架:Svelte

我们从最细的粒度,节点级更新的框架 Svelte 开始讲起(如果想了解这个框架,可以点击这里查看官网)

关于主流前端框架的本质区别

首先定义一个计数器组件,先定义组件逻辑:

  • 定义变量count,初始值为 0
  • 定义函数handleClick,每次点击时 count + 1
  • 然后定义一个渲染组件的<button>节点,将点击事件绑定为<button>节点的点击回调函数
  • 最后定义一个<p>节点,内容为一段文本

经过渲染,视图上的数字初始值为 0,每次点击都会加 1

节点级更新框架的原理分为三步:

  1. 状态变化可能导致的节点变化编译为具体方法
  2. 监听状态变化
  3. 当交互导致状态变化后,直接调用具体方法,改变对应视图

在我们上面的例子中:

  1. 变量count变化可能导致<button>节点中的文本节点发生变化,由于<p>节点不包含状态变化,所以它不会出现在编译后的 update 方法中(这种将状态变化可能导致的节点变化编译为具体方法的技术,被称为预编译,网站中实际运行的代码,都是预编译之后的代码)

  2. 监听状态变化,具体方案是采用了发布订阅设计模式,当创建一个状态后,会为状态维护一张订阅了该状态变化的表,所有需要监听变化的回调函数都在表中进行了注册,这就是发布订阅中的订阅部分

  3. 每当状态变化,会发布这张表,将状态变了这一消息发布出去,每个订阅该状态变化的回调函数都会收到通知并执行,这就是发布订阅中发布的部分

  4. 通过以上这种方式,框架能对每个状态化做出反应,这种精确到状态的更新被称为细粒度更新,这也就是节点级更新框架的工作原理。

应用级更新框架:React

讨论到应用级更新框架,这种框架会采用虚拟 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 子组件可以独立计数

  • 首屏渲染时,React 会根据应用的树结构,生成一颗对应的虚拟DOM树

关于主流前端框架的本质区别

  • 当点击 <button> 节点后,调用handleClick,触发状态更新,react 会重新生成一颗完整的虚拟 DOM 树

关于主流前端框架的本质区别

  • 新生成的每个节点会与之前的虚拟 DOM 树的同级节点进行比较,如果存在差异,记录该差异

关于主流前端框架的本质区别

  • 在上面的例子中,进行到左边的<Counter />组件的<button>节点时,发现前后两个button节点的内容不一致,就会记录下来,等新的虚拟DOM生成完毕后,将记录的差别统一渲染到视图上

总结

刚才讲过,节点级更新的框架需要监听状态的变化,与节点级框架不同,应用级框架不关心是哪个状态发生了变化,应用中的任何组件中的任何一个状态变化,都会从 root根节点创建一颗完整的虚拟DOM树,然后通过前后两棵虚拟DOM树的比较,找到变化的部分,最终将变化的部分更新到视图,主流的应用级更新框架就是React

提问

你可能会问:为什么状态变化后,要生成一颗完整的虚拟DOM树,而不是只为改变的状态对应的组件生成对应的虚拟DOM树?这样一来,就能节省很多虚拟 DOM 操作的开销,从而降低内存的开销,达到性能优化的目的

  • 如果你这么想,那么恭喜你,你发明了 Vue

组件级更新框架:Vue

作为组件级更新框架的代表,Vue2 采用虚拟 DOM + 细粒度更新实现,Vue3 则在此基础上引入了预编译,并升级了细粒度更新的实现。

复习一下吧

最后总结一下:主流前端框架的工作原理是 框架的运行机制根据状态渲染视图,他们的区别是更新粒度不同,三种更新粒度的框架分别对应不同的技术点:

更新粒度 对应技术 代表作品
应用级 虚拟DOM React
组件级 细粒度更新、预编译、虚拟DOM Vue2、Vue3
节点级 细粒度更新、预编译 Svelte
转载自:https://juejin.cn/post/7011713268297236494
评论
请登录