li-jia-nan / my-blog

个人技术博客,同步掘金,文章写在 Issues 里
43 stars 1 forks source link

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

Open li-jia-nan opened 1 year ago

li-jia-nan commented 1 year ago

前言

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

111.png

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

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

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

组件化

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

应用 => 组件 => 节点

44.png

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

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

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

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

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

答案是:更新粒度的区别

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

节点级更新框架:Svelte

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

46544.png

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

经过渲染,视图上的数字初始值为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 />
  </>
);

465454.png

57867.png

ghgh.png

总结

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

提问

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

组件级更新框架:Vue

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

复习一下吧

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

更新粒度 对应技术 代表作品
应用级 虚拟DOM React
组件级 细粒度更新、预编译、虚拟DOM Vue2、Vue3
节点级 细粒度更新、预编译 Svelte