You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
尤雨溪:在 Web 应用中,「可中断式更新」主要是由大量 CPU 计算加上复杂 DOM 操作引起的。时间分片旨在让应用在 CPU 进行大量计算时也能与用户交互,但时间分片只能对大量 CPU 计算进行优化,无法优化复杂 DOM 操作,因为要确保用户正在操作的界面是最新的状态才行。因此,我们可以考虑两种不同的可中断式更新的场景:
CPU 计算量不大,但 DOM 操作非常复杂(比如说你向页面中插入了十万个节点)。这种场景下不管你做不做时间分片,页面都会很卡。
CPU 计算量非常大。理论上时间分片在这种场景里会有较大收益,但是人机交互研究表明,除了动画之外,大部分用户不会觉得 10 毫秒和 100 毫秒有很大区别。
也就是说,时间分片只在 CPU 需要连续计算 100 毫秒以上的情况下才有较大收益。有意思的地方就出现了,在 React 经常会出现 100 毫秒以上的计算量,因为
背景
自从React16版本更新了Hook用法,同时引入了新的Fiber架构去重构整个渲染和事件处理过程,React团队引入Hook是为了更好剥离业务代码,让开发能更加友好的抽象代码,达到低耦合的函数组件目的,那么重构Diff算法,引入Fiber架构是为了什么呢? 其实只是为了能够一个目标
快速响应
,原先Diff算法时间复杂度为$$ O(n^3)$$ ,最后经过Fiber重构达到了$$ O(n) $$,这里面具体有什么门道,值得我们去深入研究一下。问题
在了解Fiber架构之前,我们需要对原有React16之前版本是有什么问题,才需要引入Fiber架构去解决该问题?
React15及以前的版本采用的是Stack Reconciler(栈协调器)架构,使用同步递归方式去创建虚拟DOM,一旦进入创建过程,就无法中断,如果创建过程超过16ms,用户就会出现页面卡顿感觉。具体可以参考下图:
因此,从网上搜索了一下React15及以前的版本反馈,的主要问题有如下几个:
为什么
为什么会出现卡顿的情况,主要原因如下:
前置知识
为了更好了解Fiber架构设计,需要提前了解一些前置知识,每个知识点其实都需要深入了解,这里只是简单描述,主要有以下几点:
单线程的 JavaScript 与多线程的浏览器
在我们学习前端知识的时候,有个结论是:
单线程的 JavaScript 与多线程的浏览器
。一个完整的web网页在浏览器显示和交互的进程(chrome为主),需要涉及到线程主要以下几个部分:
GUI 渲染线程
,负责渲染浏览器界面HTML元素,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。JavaScript引擎线程
,JS内核,负责处理Javascript脚本程序。 一直等待着任务队列中任务的到来,然后解析Javascript脚本,运行代码。定时触发器线程
,定时器setInterval与setTimeout所在线程,为什么要单独弄个线程处理定时器?是因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确事件触发线程
,用来控制事件轮询,JS引擎自己忙不过来,需要浏览器另开线程协助异步http请求线程
,在XMLHttpRequest
或fetch
在连接后是通过浏览器新开一个线程请求, 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件放到 JavaScript引擎的处理队列中等待处理。这里需要注意XMLHttpRequest
和fetch
的区别,fetch
是w3c标准化后一个专门提供给开发调用发起http的API接口,XMLHttpRequest是一个非标准化的Http请求对象,主要是可以发起http请求获取XML数据。上述就是浏览器的多线程,然后单线程的JavaScript通常指的是
JavaScript引擎线程
,为什么需要单线程?因为多线程可能会出现各种UI交互冲突问题。因此了解单线程JS需要注意几点:JS 引擎工作流程图如下:
React 生命周期
为了更好了解React Fiber架构,我们需要对比React15和React16的生命周期,具体如下:
React15的生命周期
在15版本的时候,一个完整的组件生命周期如下(按照执行顺序):
按照不同时期,执行过程是不一样,具体可以见React的生命周期更改相关文章。
React16生命周期
相比较React15,16版本基于Fiber架构主要对更新周期的函数做了调整,整个生命周期如下:
对比一下,React 16 废弃的是哪些生命周期:
这些生命周期的共性,就是它们都处于 render 阶段,都可能重复被执行,而且由于这些 API 常年被滥用,它们在重复执行的过程中都存在着不可小觑的风险。
为什么废弃这些生命周期,因为引用了Fiber架构,render 阶段是允许暂停、终止和重启的。这就导致 render 阶段的生命周期都是有可能被重复执行的。
React16生命周期图如下:
React 虚拟DOM
记住两个点:
虚拟DOM出现react生命周期的两个节点:
为什么需要虚拟DOM?并不是因为虚拟DOM有更高的性能,而是因为虚拟 DOM 的优越之处在于,它能够在提供更爽、更高效的研发模式(也就是函数式的 UI 编程方式)的同时,仍然保持一个还不错的性能。解决了以下问题:
而在虚拟DOM这一块,Fiber架构的引入,最大的调整就是虚拟DOM更新中的diff算法,由于分片渲染,不需要一次将diff执行,可以分批计算从而减少diff算法的复杂度。
Stack Reconciler(栈协调器)
在了解Fiber架构之前,需要对React15的Stack Reconciler(栈协调器)做一次完整了解。先了解一下什么Reconciler协调器,在React中是这么定义的:
所以实现Reconciler,其实就是实现虚拟DOM到真实DOM渲染的整个逻辑过程,因此调和 !== Diff,但是Diff 确实是调和过程中最具代表性的一环。
那么要了解React15是如何实现Stack Reconciler,最重要的两块:
同步
更新渲染Diff算法策略要点:(主要是树递归)
Fiber架构
我们先来看看 React 团队在“React 哲学”中对 React 的定位:
快速响应
是React哲学理念,因此Fiber架构的出现是为了让React框架能更加快速响应用户的操作。是什么
什么是 Fiber?从字面上来理解,Fiber 这个单词翻译过来是“丝、纤维”的意思,是比线还要细的东西。在计算机科学里,我们有进程、线程之分,而 Fiber 就是比线程还要纤细的一个过程,也就是所谓的“纤程”。纤程的出现,意在对渲染过程实现更加精细的控制。
Fiber的概念理解:
从架构角度理解Fiber:
怎么解决问题
有了Fiber架构,怎么解决React15所面临的问题,虚拟DOM同步渲染真实DOM导致页面卡顿?
可以参考下图,了解一下Fiber架构工作图:
当然这样子讲只是简单的原理,还需要弄明白异步后可能产生更多问题?比如如何定制优先级,当两个同样优先级的任务相遇的时候如何解决,这些放在第二章讲解。
总结
经过第一篇Fiber文章学习,大概了解到Fiber架构出现的背景和原因,以及它是什么,是如何工作的解决之前所遇到问题。简单总结一下:
后续深入了解请看第二篇章《从React中学习Fiber架构(二)》。
额外话题(Vue.js对比)
相比较React做Fiber架构优化,主要是针对事件做了时间分片,那么为什么Vue3(Vue@next)版本并不需要做呢?Vue.js作者尤雨溪是这样子回答的:
进行汇总一下描述,Vue3之所以没有使用Fiber架构,主要有以下几个原因:
基础概念
AOT vs JIT
The text was updated successfully, but these errors were encountered: