新的git知识仓库 前端从入门到入土 ~求关注、star及整理需求,不定时更新~
什么是 Fiber ?
React Fiber是对核心算法的一次重新实现, 是异步渲染 ui 的解决方案
出现的背景
在react15中,更新过程是同步的。当我们调用setState
更新页面的时候,React 会遍历应用的所有节点,计算出差异,然后再更新 UI。整个过程是一气呵成,不能被打断的。
如果页面元素很多,组件树很大的时候,因为更新过程是同步地一层组件套一层组件,逐渐深入的过程,在更新完所有组件之前不停止,函数的调用栈调用得很深,而且很长时间不会返回。整个过程占用的时间可能超过 16 毫秒,就容易出现掉帧的现象。
举个例子,如果有200个组件要更新,每个组件花费1毫秒,更新完成总共需要200毫秒,在这200毫秒的更新过程中,浏览器唯一的主线程都在专心处理更新操作,无暇去做任何其他的事情。
如果在这200毫秒内,用户往一个input元素中输入内容,那么敲击键盘不会获得任何响应,因为渲染输入按键结果也是浏览器主线程的工作,但是浏览器主线程被React占用,抽不出空。等React更新过程结束之后,那些字符才会一下子出现在input元素里。
因为JavaScript单线程的特点,JS 运算、页面布局和页面绘制都是运行在浏览器的主线程当中,他们之间是互斥的关系。如果每个同步任务耗时太长, JS 运算持续占用主线程,程序不会对其他动作作出响应,页面也没法得到及时的更新。
React的更新过程犯了这个禁忌,而React Fiber就是要改变现状。
Fiber 的解题思路
解决主线程长时间被 JS 运算占用这一问题的基本思路,是将运算切割为多个步骤,分批完成。也就是说在完成一部分任务之后,将控制权交回给浏览器,让浏览器有时间进行页面的渲染。等浏览器忙完之后,再继续之前未完成的任务。
虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。
旧版 React 通过递归的方式进行渲染,使用的是 JS 引擎自身的函数调用栈,它会一直执行到栈空为止。而Fiber实现了自己的组件调用栈,它以链表的形式遍历组件树,可以灵活的暂停、继续和丢弃执行的任务。
实现方式是使用了浏览器的requestIdleCallback这一 API。
React 框架内部的运作可以分为 3 层:
- Virtual DOM 层,描述页面长什么样。
- Reconciler 层,负责调用组件生命周期方法,进行 Diff 运算等。
- Renderer 层,根据不同的平台,渲染出相应的页面,比较常见的是 ReactDOM 和 ReactNative。
改动最大的当属 Reconciler 层。改动后的 Reconciler 层 称为 Fiber Reconciler
,它每执行一段时间,会将控制权交还给浏览器。相对应的,将以前的 Reconciler 被命名为Stack Reconciler
。Stack Reconciler
运作的过程是不能被打断的,必须一条道走到黑。
React Fiber把更新过程碎片化,每执行完一段更新过程,就把控制权交还给React负责任务协调的模块,看看有没有其他紧急任务要做,如果没有就继续去更新,如果有紧急任务,那就去做紧急任务。
为了达到这种效果,就需要有一个调度器 (Scheduler) 来进行任务分配。任务的优先级有六种:
- synchronous,与之前的Stack Reconciler操作一样,同步执行
- task,在next tick之前执行
- animation,下一帧之前执行
- high,在不久的将来立即执行
- low,稍微延迟执行也没关系
- offscreen,下一次render时或scroll时才执行
优先级高的任务(如键盘输入)可以打断优先级低的任务(如Diff)的执行,从而更快的生效。
Fiber Reconciler
在执行过程中,会分为 2 个阶段。
-
阶段一,生成 Fiber 树,得出需要更新的节点信息。这一步是一个渐进的过程,可以被打断。
该阶段包括- componentWillMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
-
阶段二,将需要更新的节点一次性批量更新,这个过程不能被打断。
该阶段包括- componentDidMount
- componentDidUpdate
- componentWillUnmount
Fiber树
Fiber 其实指的是一种数据结构,而Fiber树本质来说是一个链表。
阶段一有两颗树,Virtual DOM 树和 Fiber 树,Fiber 树是在 Virtual DOM 树的基础上通过额外信息生成的。
Fiber 树在首次渲染的时候会一次生成。在后续需要 Diff 的时候,会根据已有树和最新 Virtual DOM 的信息,生成一棵新的树。这颗新树每生成一个新的节点,都会将控制权交回给主线程,去检查有没有优先级更高的任务需要执行。如果没有,则继续构建树的过程。
如果过程中有优先级更高的任务需要进行,则 Fiber Reconciler 会丢弃正在生成的树,在空闲的时候再重新执行一遍。
题外话
这里会引出一个知识点,就是在react更新过程中,shouldComponentUpdate
、componentWillUpdate
等函数会执行几次。当然,答案是:多次。
因此,如果有在阶段一的函数中执行的逻辑,必须保证结果的一致性。另外,如果在这几个函数中有网络请求等逻辑的话,务必对可能的重复调用做处理。
求赞?~
求关注~
相关阅读
- react-app-rewired:不使用eject修改create-creact-app配置文件
- react hook防抖及节流
参考文档
- React Fiber是什么
- React.Fiber
- [React Fiber 原理介绍](
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!