共计 12258 个字符,预计需要花费 31 分钟才能阅读完成。
React Fiber 是 Facebook 破费两年余工夫对 React 做出的一个重大扭转与优化,是 对 React 外围算法的一次从新实现。从 Facebook 在 React Conf 2017 会议上确认,React Fiber 会在 React 16 版本公布至今,也已过来三年无余,现在,React 17 业已公布,社区对于 Fiber 的优良文章不在少数。
本文 源于一次团队外部的技术分享 ,借鉴社区优良文章,联合集体了解,进行 整合 ,从六个问题登程,对 React Fiber 进行了解与意识,同时对时下热门的前端框架Svelte 进行简要介绍与分析,心愿对正在探索 React 及各前端框架的小伙伴们能有所助益。
全文大量参考和援用以下几篇博文,读者可自行查阅:
- React 技术揭秘
- 前端工程师的自我涵养:React Fiber 是如何实现更新过程可控的
- 新兴前端框架 Svelte 从入门到原理
- 以 React 为例,说说框架和性能(下)
一、React 的设计理念是什么?
React 官网在 React 哲学一节开篇提到:
咱们认为,React 是用 JavaScript 构建 疾速响应 的大型 Web 应用程序的首选形式。它在 Facebook 和 Instagram 上体现优良。React 最棒的局部之一是疏导咱们思考如何构建一个利用。
由此可见,React 谋求的是“疾速响应”,那么,“疾速响应“的制约因素都有什么呢?
- CPU 的瓶颈:当我的项目变得宏大、组件数量繁多、遇到 大计算量 的操作或者 设施性能有余 使得页面掉帧,导致卡顿。
- IO 的瓶颈:发送网络申请后,因为须要期待数据返回能力进一步操作导致不能疾速响应。
本文要聊的 fiber 架构次要就是用来解决 CPU 和网络的问题,这两个问题始终也是最影响前端开发体验的中央,一个会造成 卡顿 ,一个会造成 白屏。为此 react 为前端引入了两个新概念:Time Slicing 工夫分片和 Suspense。
二、React 的“先天不足”—— 据说 Vue 3.0 采纳了动静联合的 Dom diff,React 为何不跟进?
Vue 3.0 动静联合的 Dom diff
Vue3.0 提出动静联合的 DOM diff 思维,动静联合的 DOM diff 其实是在预编译阶段进行了优化。之所以可能做到 预编译优化 ,是因为 Vue core 能够 动态剖析 template,在解析模版时,整个 parse 的过程是利用 正则表达式 程序解析模板,当解析到开始标签、闭合标签和文本的时候都会别离执行对应的回调函数,来达到结构 AST 树的目标。
借助预编译过程 ,Vue 能够做到的预编译优化就很弱小了。比方在预编译时标记出模版中可能变动的组件节点,再次进行渲染前 diff 时就能够 跳过“永远不会变动的节点”,而只须要比照“可能会变动的动静节点”。这也就是 动静联合的 DOM diff 将 diff 老本与模版大小正相干优化到与动静节点正相干的理论依据。
React 是否像 Vue 那样进行预编译优化?
Vue 须要做数据双向绑定,须要进行数据拦挡或代理,那它就须要在 预编译阶段动态剖析模版,剖析出视图依赖了哪些数据,进行响应式解决 。而 React 就是 部分从新渲染 ,React 拿到的或者说主持的,所负责的就是一堆 递归 React.createElement 的执行调用(参考下方通过 Babel 转换的代码),它无奈从模版层面进行动态剖析。JSX 和手写的 render function 是齐全动静的,适度的灵活性导致运行时能够用于优化的信息有余。
JSX 写法:
<div>
<h1> 六个问题助你了解 React Fiber</h1>
<ul>
<li>React</li>
<li>Vue</li>
</ul>
</div>
递归 React.createElement:
// Babel 转换后
React.createElement(
"div",
null,
React.createElement(
"h1",
null,
"\u516D\u4E2A\u95EE\u9898\u52A9\u4F60\u7406\u89E3 React Fiber"
),
React.createElement(
"ul",
null,
React.createElement("li", null, "React"),
React.createElement("li", null, "Vue")
)
);
JSX vs Template
- JSX 具备 JavaScript 的残缺表现力,能够构建非常复杂的组件。然而 灵便 的语法,也意味着 引擎难以了解,无奈预判开发者的用户用意,从而难以优化性能。
- Template 模板是一种十分有 束缚 的语言,你只能以某种形式去编写模板。
既然存在以上 编译时先天不足 ,在运行时优化方面,React 始终在致力。比方,React15 实现了 batchedUpdates(批量更新)。即 同一事件回调函数上下文 中的屡次 setState 只会触发一次更新。
然而,如果单次更新就很耗时,页面还是会卡顿(这在一个保护工夫很长的大利用中是很常见的)。这是因为 React15 的更新流程是同步执行的,一旦开始更新直到页面渲染前都不能中断。
材料参考:以 React 为例,说说框架和性能(下)| 新兴前端框架 Svelte 从入门到原理
三、从架构演变看一直进击的 React 都做过哪些优化?
React 渲染页面的两个阶段
- 调度阶段(reconciliation):在这个阶段 React 会更新数据生成新的 Virtual DOM,而后通过 Diff 算法,疾速找出须要更新的元素,放到更新队列中去,失去新的更新队列。
- 渲染阶段(commit):这个阶段 React 会遍历更新队列,将其所有的变更一次性更新到 DOM 上。
React 15 架构
React15 架构能够分为两层:
- Reconciler(协调器)—— 负责找出变动的组件;
- Renderer(渲染器)—— 负责将变动的组件渲染到页面上;
在 React15 及以前,Reconciler 采纳递归的形式创立虚构 DOM,递归过程是不能中断的。如果组件树的层级很深,递归会占用线程很多工夫,递归更新工夫超过了 16ms,用户交互就会卡顿。
为了解决这个问题,React16 将递归的无奈中断的更新重构为 异步的可中断更新,因为已经用于递归的虚构 DOM 数据结构曾经无奈满足需要。于是,全新的 Fiber 架构应运而生。
React 16 架构
为了解决同步更新长时间占用线程导致页面卡顿的问题,也为了摸索运行时优化的更多可能,React 开始重构并始终继续至今。重构的指标是实现 Concurrent Mode(并发模式)。
从 v15 到 v16,React 团队花了两年工夫将源码架构中的 Stack Reconciler 重构为 Fiber Reconciler。
React16 架构能够分为三层:
- Scheduler(调度器)—— 调度工作的优先级,高优工作优先进入 Reconciler;
- Reconciler(协调器)—— 负责找出变动的组件:更新工作从递归变成了能够中断的循环过程。Reconciler 外部采纳了 Fiber 的架构;
- Renderer(渲染器)—— 负责将变动的组件渲染到页面上。
React 17 优化
React16 的 expirationTimes 模型 只能辨别是否 >=expirationTimes
决定节点是否更新。React17 的 lanes 模型 能够选定一个更新区间,并且动静的向区间中增减优先级,能够解决更细粒度的更新。
Lane 用 二进制位 示意工作的优先级,不便优先级的计算(位运算),不同优先级占用不同地位的“赛道”,而且存在批的概念,优先级越低,“赛道”越多。高优先级打断低优先级,新建的工作须要赋予什么优先级等问题都是 Lane 所要解决的问题。
Concurrent Mode 的目标是实现一套可中断 / 复原的更新机制。其由两局部组成:
- 一套协程架构:Fiber Reconciler
- 基于协程架构的启发式更新算法:管制协程架构工作形式的算法
材料参考:React17 新个性:启发式更新算法
四、浏览器一帧都会干些什么以及 requestIdleCallback 的启发
浏览器一帧都会干些什么?
咱们都晓得,页面的内容都是一帧一帧绘制进去的,浏览器刷新率代表浏览器一秒绘制多少帧。原则上说 1s 内绘制的帧数也多,画面体现就也细腻。目前浏览器大多是 60Hz(60 帧 /s),每一帧耗时也就是在 16.6ms 左右。那么在这一帧的(16.6ms)过程中浏览器又干了些什么呢?
通过下面这张图能够分明的晓得,浏览器一帧会通过上面这几个过程:
- 承受输出事件
- 执行事件回调
- 开始一帧
- 执行 RAF (RequestAnimationFrame)
- 页面布局,款式计算
- 绘制渲染
- 执行 RIC (RequestIdelCallback)
第七步的 RIC 事件不是每一帧完结都会执行,只有在一帧的 16.6ms 中做完了后面 6 件事儿且还有剩余时间,才会执行。如果一帧执行完结后还有工夫执行 RIC 事件,那么下一帧须要在事件执行完结能力持续渲染,所以 RIC 执行不要超过 30ms,如果长时间不将控制权交还给浏览器,会影响下一帧的渲染,导致页面呈现卡顿和事件响应不及时。
requestIdleCallback 的启发
咱们以浏览器是否有剩余时间作为工作中断的规范,那么咱们须要一种机制,当浏览器有剩余时间时告诉咱们。
requestIdleCallback((deadline) => {
// deadline 有两个参数
// timeRemaining(): 以后帧还剩下多少工夫
// didTimeout: 是否超时
// 另外 requestIdleCallback 后如果跟上第二个参数 {timeout: ...} 则会强制浏览器在以后帧执行完后执行。if (deadline.timeRemaining() > 0) {// TODO} else {requestIdleCallback(otherTasks);
}
});
// 用法示例
var tasksNum = 10000
requestIdleCallback(unImportWork)
function unImportWork(deadline) {while (deadline.timeRemaining() && tasksNum > 0) {console.log(` 执行了 ${10000 - tasksNum + 1}个工作 `)
tasksNum--
}
if (tasksNum > 0) { // 在将来的帧中继续执行
requestIdleCallback(unImportWork)
}
}
其实局部浏览器曾经实现了这个 API,这就是 requestIdleCallback。然而因为以下因素,Facebook 摈弃了 requestIdleCallback 的原生 API:
- 浏览器兼容性;
- 触发频率不稳固,受很多因素影响。比方当咱们的浏览器切换 tab 后,之前 tab 注册的 requestIdleCallback 触发的频率会变得很低。
参考:requestIdleCallback 的 FPS 只有 20
基于以上起因,在 React 中实现了性能更齐备的 requestIdleCallbackpolyfill,这就是Scheduler。除了在闲暇时触发回调的性能外,Scheduler 还提供了多种调度优先级供工作设置。
材料参考:requestIdleCallback- 后台任务调度
五、Fiber 为什么是 React 性能的一个飞跃?
什么是 Fiber
Fiber 的英文含意是“纤维”,它是比线程(Thread)更细的线,比线程(Thread)管制得更精细的执行模型。在狭义计算机科学概念中,Fiber 又是一种合作的(Cooperative)编程模型(协程),帮忙开发者用一种【既模块化又合作化】的形式来编排代码。
在 React 中,Fiber 就是 React 16 实现的一套新的更新机制,让 React 的更新过程变得可控,防止了之前采纳递归须要零打碎敲影响性能的做法。
React Fiber 中的工夫分片
把一个 耗时长的工作分成很多小片 ,每一个小片的运行工夫很短,尽管总工夫仍然很长,然而在每个小片执行完之后,都 给其余工作一个执行的机会,这样惟一的线程就不会被独占,其余工作仍然有运行的机会。
React Fiber 把更新过程 碎片化,每执行完一段更新过程,就把控制权交还给 React 负责工作协调的模块,看看有没有其余紧急任务要做,如果没有就持续去更新,如果有紧急任务,那就去做紧急任务。
Stack Reconciler
基于栈的 Reconciler,浏览器引擎会从执行栈的顶端开始执行,执行结束就弹出以后执行上下文,开始执行下一个函数,直到执行栈被清空才会进行。而后将执行权交还给浏览器。因为 React 将页面视图视作一个个函数执行的后果。每一个页面往往由多个视图组成,这就意味着多个函数的调用。
如果一个页面足够简单,造成的函数调用栈就会很深。每一次更新,执行栈须要一次性执行实现,中途不能干其余的事儿,只能 ”全心全意 “。联合后面提到的浏览器刷新率,JS 始终执行,浏览器得不到控制权,就不能及时开始下一帧的绘制。如果这个工夫超过 16ms,当页面有动画成果需要时,动画因为浏览器 不能及时绘制下一帧,这时动画就会呈现卡顿。不仅如此,因为事件响应代码是在每一帧开始的时候执行,如果不能及时绘制下一帧,事件响应也会提早。
Fiber Reconciler
链表构造
在 React Fiber 中 用链表遍历的形式代替了 React 16 之前的栈递归计划。在 React 16 中应用了大量的链表。
- 应用多向链表的模式代替了原来的树结构;
<div id="A">
A1
<div id="B1">
B1
<div id="C1"></div>
</div>
<div id="B2">
B2
</div>
</div>
- 副作用单链表;
- 状态更新单链表;
- …
链表是一种简略高效的数据结构,它在以后节点中保留着指向下一个节点的指针;遍历的时候,通过操作指针找到下一个元素。
链表相比程序构造数据格式的 益处 就是:
- 操作更高效,比方程序调整、删除,只须要扭转节点的指针指向就好了。
- 不仅能够依据以后节点找到下一个节点,在多向链表中,还能够找到他的父节点或者兄弟节点。
但链表也不是完满的,毛病 就是:
- 比程序构造数据更占用空间,因为每个节点对象还保留有指向下一个对象的指针。
- 不能自在读取,必须找到他的上一个节点。
React 用 空间换工夫 ,更高效的操作能够不便依据优先级进行操作。同时 能够依据以后节点找到其余节点,在上面提到的挂起和复原过程中起到了关键作用。
斐波那契数列的 Fiber
递归模式的斐波那契数列写法:
function fib(n) {if (n <= 2) {return 1;} else {return fib(n - 1) + fib(n - 2);
}
}
采纳 Fiber 的思路 将其改写为循环(这个例子并不能和 React Fiber 的对等):
function fib(n) {let fiber = { arg: n, returnAddr: null, a: 0}, consoled = false;
// 标记循环
rec: while (true) {
// 当开展齐全后,开始计算
if (fiber.arg <= 2) {
let sum = 1;
// 寻找父级
while (fiber.returnAddr) {if(!consoled) {
// 在这里打印查看造成的链表模式的 fiber 对象
consoled=true
console.log(fiber)
}
fiber = fiber.returnAddr;
if (fiber.a === 0) {
fiber.a = sum;
fiber = {arg: fiber.arg - 2, returnAddr: fiber, a: 0};
continue rec;
}
sum += fiber.a;
}
return sum;
} else {
// 先开展
fiber = {arg: fiber.arg - 1, returnAddr: fiber, a: 0};
}
}
}
六、React Fiber 是如何实现更新过程可控?
更新过程的可控次要体现在上面几个方面:
- 工作拆分
- 工作挂起、复原、终止
- 工作具备优先级
工作拆分
在 React Fiber 机制中,它采纳 ”化整为零 “ 的思维,将和谐阶段(Reconciler)递归遍历 VDOM 这个大工作分成若干小工作,每个工作只负责 一个节点 的解决。
工作挂起、复原、终止
workInProgress tree
workInProgress 代表 以后正在执行更新的 Fiber 树 。在 render 或者 setState 后,会构建一颗 Fiber 树,也就是 workInProgress tree,这棵树在构建每一个节点的时候会 收集以后节点的副作用 ,整棵树构建实现后,会造成一条残缺的 副作用链。
currentFiber tree
currentFiber 示意 上次渲染构建的 Filber 树 。 在每一次更新实现后 workInProgress 会赋值给 currentFiber。在新一轮更新时 workInProgress tree 再从新构建,新 workInProgress 的节点通过 alternate 属性和 currentFiber 的节点建立联系。
在新 workInProgress tree 的创立过程中,会同 currentFiber 的对应节点进行 Diff 比拟,收集副作用。同时也会 复用 和 currentFiber 对应的节点对象,缩小新创建对象带来的开销。也就是说 无论是创立还是更新、挂起、复原以及终止操作都是产生在 workInProgress tree 创立过程中的。workInProgress tree 构建过程其实就是循环的执行工作和创立下一个工作。
挂起
当第一个小工作实现后,先判断这一帧是否还有 闲暇工夫 ,没有就挂起下一个工作的执行, 记住 以后挂起的节点,让出控制权给浏览器执行更高优先级的工作。
复原
在浏览器渲染完一帧后,判断以后帧是否有 剩余时间,如果有就复原执行之前挂起的工作。如果没有工作须要解决,代表和谐阶段实现,能够开始进入渲染阶段。
- 如何判断一帧是否有闲暇工夫的呢?
应用后面提到的 RIC (RequestIdleCallback) 浏览器原生 API,React 源码中为了兼容低版本的浏览器,对该办法进行了 Polyfill。
- 复原执行的时候又是如何晓得下一个工作是什么呢?
答案是在后面提到的 链表。在 React Fiber 中每个工作其实就是在解决一个 FiberNode 对象,而后又生成下一个工作须要解决的 FiberNode。
终止
其实并不是每次更新都会走到提交阶段。当在和谐过程中触发了新的更新,在执行下一个工作的时候,判断 是否有优先级更高的执行工作 ,如果有就终止原来将要执行的工作,开始新的 workInProgressFiber 树构建过程,开始新的更新流程。这样能够防止反复更新操作。这也是 在 React 16 当前生命周期函数 componentWillMount 有可能会执行屡次 的起因。
工作具备优先级
React Fiber 除了通过挂起,复原和终止来管制更新外,还给每个任务分配了优先级。具体点就是在创立或者更新 FiberNode 的时候,通过算法给每个任务分配一个到期工夫(expirationTime)。在每个工作执行的时候除了判断剩余时间,如果以后解决节点曾经过期,那么无论当初是否有闲暇工夫都必须执行该工作。过期工夫的大小还代表着工作的优先级。
工作在执行过程中顺便收集了每个 FiberNode 的副作用,将有副作用的节点通过 firstEffect、lastEffect、nextEffect 造成一条副作用单链表 A1(TEXT)-B1(TEXT)-C1(TEXT)-C1-C2(TEXT)-C2-B1-B2(TEXT)-B2-A。
其实 最终都是为了收集到这条副作用链表,有了它,在接下来的渲染阶段就通过遍历副作用链实现 DOM 更新 。这里须要留神, 更新实在 DOM 的这个动作是零打碎敲的,不能中断,不然会造成视觉上的不连贯(commit)。
<div id="A1">
A1
<div id="B1">
B1
<div id="C1">C1</div>
<div id="C2">C2</div>
</div>
<div id="B2">
B2
</div>
</div>
直观展现
正是基于以上这些过程,应用 Fiber,咱们就有了在社区常常看到的两张比照图。
清晰展现及交互、源码可通过上面两个链接进入,查看网页源代码。
- Stack Example
- Fiber Example
Fiber 构造长什么样?
基于工夫分片的增量更新须要 更多的上下文信息,之前的 vDOM tree 显然难以满足,所以扩大出了 fiber tree(即 Fiber 上下文的 vDOM tree),更新过程就是依据输出数据以及现有的 fiber tree 结构出新的 fiber tree(workInProgress tree)。
FiberNode 上的属性有很多,依据笔者的了解,以下这么几个属性是值得关注的:return、child、sibling(次要负责 fiber 链表的链接);stateNode;effectTag;expirationTime;alternate;nextEffect。各属性介绍参看上面的class FiberNode
:
class FiberNode {constructor(tag, pendingProps, key, mode) {
// 实例属性
this.tag = tag; // 标记不同组件类型,如函数组件、类组件、文本、原生组件...
this.key = key; // react 元素上的 key 就是 jsx 上写的那个 key,也就是最终 ReactElement 上的
this.elementType = null; // createElement 的第一个参数,ReactElement 上的 type
this.type = null; // 示意 fiber 的实在类型,elementType 根本一样,在应用了懒加载之类的性能时可能会不一样
this.stateNode = null; // 实例对象,比方 class 组件 new 完后就挂载在这个属性下面,如果是 RootFiber,那么它下面挂的是 FiberRoot, 如果是原生节点就是 dom 对象
// fiber
this.return = null; // 父节点,指向上一个 fiber
this.child = null; // 子节点,指向本身上面的第一个 fiber
this.sibling = null; // 兄弟组件, 指向一个兄弟节点
this.index = 0; // 个别如果没有兄弟节点的话是 0 当某个父节点下的子节点是数组类型的时候会给每个子节点一个 index,index 和 key 要一起做 diff
this.ref = null; // reactElement 上的 ref 属性
this.pendingProps = pendingProps; // 新的 props
this.memoizedProps = null; // 旧的 props
this.updateQueue = null; // fiber 上的更新队列执行一次 setState 就会往这个属性上挂一个新的更新, 每条更新最终会造成一个链表构造,最初做批量更新
this.memoizedState = null; // 对应 memoizedProps,上次渲染的 state,相当于以后的 state,了解成 prev 和 next 的关系
this.mode = mode; // 示意以后组件下的子组件的渲染形式
// effects
this.effectTag = NoEffect; // 示意以后 fiber 要进行何种更新(更新、删除等)this.nextEffect = null; // 指向下个须要更新的 fiber
this.firstEffect = null; // 指向所有子节点里,须要更新的 fiber 里的第一个
this.lastEffect = null; // 指向所有子节点中须要更新的 fiber 的最初一个
this.expirationTime = NoWork; // 过期工夫,代表工作在将来的哪个工夫点应该被实现
this.childExpirationTime = NoWork; // child 过期工夫
this.alternate = null; // current 树和 workInprogress 树之间的互相援用
}
}
图片起源:齐全了解 React Fiber
function performUnitWork(currentFiber){//beginWork(currentFiber) // 找到儿子,并通过链表的形式挂到 currentFiber 上,每一偶儿子就找前面那个兄弟
// 有儿子就返回儿子
if(currentFiber.child){return currentFiber.child;}
// 如果没有儿子,则找弟弟
while(currentFiber){// 始终往上找
//completeUnitWork(currentFiber);// 将本人的副作用挂到父节点去
if(currentFiber.sibling){return currentFiber.sibling}
currentFiber = currentFiber.return;
}
}
Concurrent Mode(并发模式)
Concurrent Mode 指的就是 React 利用下面 Fiber 带来的新个性的开启的新模式 (mode)。react17 开始反对 concurrent mode,这种模式的基本目标是为了 让利用放弃 cpu 和 io 的疾速响应 ,它是一组新性能, 包含 Fiber、Scheduler、Lane,能够依据用户硬件性能和网络情况调整利用的响应速度,外围就是为了 实现异步可中断的更新。concurrent mode 也是将来 react 次要迭代的方向。
目前 React 试验版本容许用户抉择三种 mode:
- Legacy Mode: 就相当于目前稳定版的模式
- Blocking Mode: 应该是当前会代替 Legacy Mode 而长期存在的模式
- Concurrent Mode: 当前会变成 default 的模式
Concurrent Mode 其实开启了一堆新个性,其中有两个最重要的个性能够用来解决咱们结尾提到的两个问题:
- Suspense:Suspense 是 React 提供的一种 异步解决的机制, 它不是一个具体的数据申请库。它是 React 提供的原生的组件异步调用原语。
- useTrasition:让页面实现
Pending -> Skeleton -> Complete
的更新门路, 用户在切换页面时能够停留在以后页面,让页面放弃响应。相比展现一个无用的空白页面或者加载状态,这种 用户体验 更加敌对。
其中 Suspense 能够用来解决申请阻塞的问题,UI 卡顿的问题其实开启 concurrent mode 就曾经解决的,但如何利用 concurrent mode 来实现更敌对的交互还是须要对代码做一番改变的。
材料参考:Concurrent 模式介绍 (实验性) | 了解 React Fiber & Concurrent Mode | 11.concurrent mode(并发模式是什么样的) | 人人都能读懂的 react 源码解析
将来可期
Concurrent Mode 只是并发,既然工作可拆分(只有最终失去残缺 effect list 就行),那就容许 并行 执行,(多个 Fiber reconciler + 多个 worker),首屏也更容易分块加载 / 渲染(vDOM 森林。
并行渲染的话,据说 Firefox 测试结果显示,130ms 的页面,只须要 30ms 就能搞定,所以在这方面是值得期待的,而 React 曾经做好筹备了,这也就是在 React Fiber 上下文常常听到的待 unlock 的更多个性之一。
isInputPending —— Fiber 架构思维对前端生态的影响
Facebook 在 Chromium 中提出并实现了 isInputPending() API
,它能够进步网页的响应能力,然而不会对性能造成太大影响。Facebook 提出的 isInputPending API
是第一个将 中断的概念 用于浏览器用户交互的的性能,并且容许 JavaScript 可能查看事件队列而不会将控制权交于浏览器。
目前 isInputPending API 仅在 Chromium 的 87 版本开始提供,其余浏览器并未实现。
材料参考:Facebook 将对 React 的优化实现到了浏览器!| Faster input events with Facebook’s first browser API contribution
Svelte 对固有模式的冲击
当下前端畛域,三大框架 React、Vue、Angular 版本逐步稳固,如果说前端行业会呈现哪些框架有可能会挑战 React 或者 Vue 呢?很多人认为 Svelte 应该是其中的选项之一。
Svelte 叫法是 [Svelte]
, 本意是苗条纤瘦的,是一个新兴热门的前端框架。在开发者满意度、趣味度、市场占有率上 均名落孙山,同时,它有更小的打包体积,更少的开发代码书写,在性能测评中,与 React、Vue 相比,也不遑多让。
Svelte 的核心思想在于『通过动态编译缩小框架运行时的代码量』。
Svelte 劣势有哪些
- No Runtime —— 无运行时代码
- Less-Code —— 写更少的代码
- Hight-Performance —— 高性能
Svelte 劣势
- 社区
- 社区
- 社区
原理概览
Svelte 在 编译时,就曾经剖析好了数据 和 DOM 节点之间的对应关系,在数据发生变化时,能够十分高效的来更新 DOM 节点。
- Rich Harris 在进行 Svelte 的设计的时候 没有采纳 Virtual DOM,次要是因为他感觉 Virtual DOM Diff 的过程是十分低效的。具体可参考 Virtual Dom 真的高效吗一文;Svelte 采纳了 Templates 语法,在编译的过程中就进行优化操作;
- Svelte 记录脏数据的形式:位掩码(bitMask);
- 数据和 DOM 节点之间的对应关系:React 和 Vue 是通过 Virtual Dom 进行 diff 来算进去更新哪些 DOM 节点效率最高。Svelte 是在编译时候,就记录了数据 和 DOM 节点之间的对应关系,并且保留在 p 函数中。
材料参考:新兴前端框架 Svelte 从入门到原理
材料参考与举荐
- React 技术揭秘
- 前端工程师的自我涵养:React Fiber 是如何实现更新过程可控的
- 新兴前端框架 Svelte 从入门到原理
- 以 React 为例,说说框架和性能(下)