React Fiber源码分析 (介绍)
写了分析源码的文章后, 总觉得缺少了什么, 在这里补一个整体的总结,输出个人的理解~
文章的系列标题为Fiber源码分析, 那么什么是Fiber,官方给出的解释是:
React Fiber是对核心算法的一次重新实现。
ummm, 这样说实在是有点泛,详细分析一下
先从开发者角度来看
实际上这次更新对于我们来说影响并不大,只是几个生命周期改变了,新引入的两个生命周期函数 getDerivedStateFromProps
,getSnapshotBeforeUpdate
以及在未来 v17.0 版本中即将被移除的三个生命周期函数componentWillMount,componentWillReeiveProps,componentWillUpdate,目前版本并不会影响原生命周期的使用,但不能和新的生命周期一起使用,也会被标记为不安全,下图为目前React的流程图:
其他的几乎没有任何影响,我们还是照常的写着原来的代码,然后我们就感觉到网页性能更高了一些。
为什么网页性能会变高,Fiber做了什么?
要回答这个问题,需要回头看javascript是单线程的知识点。
单线程一次只能做一件事, 在原来的React中, 如果一次更新的时间比较长,那么用户就会感觉到卡顿,也就是丢帧了。
打个比方, 假如我现在要更新1000个组件(往大了说),每个组件平均花时间1ms,那么在1s内,浏览器的整个线程都被阻塞了,这时候用户在input上的任何操作都不会有反应,等到更新完毕,界面上突的一下就显示了原来用户的输入,这个体验是非常差的。这里借用官方一张图, Fiber之前的版本就是这样,调用栈非常深
那么Fiber,现在是怎么做呢?
Fiber实际上是把一次更新拆成一个个的单元任务,每次做完一个单元任务后,就询问是否有更高的优先级任务,有就去执行,回头再来干这件事,如图
那么就明白了,Fiber是一个任务调和器!, 同样,我们根据这个来分析Fiber具体做了什么
Fiber具体做了什么
首先,要做到这样的效果,那么就需要有以下的功能:
1.可分片 (拆分任务)
2.可中断 (执行另一个任务后, 可以回头继续执行未完成的任务)
3.具备优先级 (哪个任务先执行)
想要做到拆分任务就需要任务可以分片,也就是React的Fiber,fiber即为一个分片任务,贴上数据结构:
可中断即是使用了队列的形式保存任务, 具体可以看源码~
基本是一个fiber即为一个组件,而优先级即使用fiber的expirationTime属性, expirationTime越小即优先级越高
function FiberNode(tag, pendingProps, key, mode) {
// Instance
this.tag = tag;
this.key = key;
this.elementType = null;
this.type = null;
this.stateNode = null; // Fiber
this.return = null;
this.child = null;
this.sibling = null;
this.index = 0; this.ref = null; this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.firstContextDependency = null; this.mode = mode; // Effects
this.effectTag = NoEffect;
this.nextEffect = null; this.firstEffect = null;
this.lastEffect = null; this.expirationTime = NoWork;
this.childExpirationTime = NoWork; this.alternate = null; }
从数据结构上, 有几个属性值得说一下,
首先是官方注释了Fiber的几个属性, 这几个是非常重要的
原来的React更新任务是采用递归的形式, 那么现在如果任务想中断, 在递归中是很难做处理的, 所以React改成了大循环的模式
修改了生命周期也是因为任务可中断~
具体可以参考下面这篇文章
到目前为止(React 16.4),React的渲染机制遵循同步渲染:
1) 首次渲染: willMount > render > didMount,
2) props更新时: receiveProps > shouldUpdate > willUpdate > render > didUpdate
3) state更新时: shouldUpdate > willUpdate > render > didUpdate
3) 卸载时: willUnmount 期间每个周期函数各司其职,输入输出都是可预测,一路下来很顺畅。 BUT 从React 17 开始,渲染机制将会发生颠覆性改变,这个新方式就是 Async Render。 首先,async render不是那种服务端渲染,比如发异步请求到后台返回newState甚至新的html,这里的async render还是限制在React作为一个View框架的View层本身。 通过进一步观察可以发现,预废弃的三个生命周期函数都发生在虚拟dom的构建期间,也就是render之前。在将来的React 17中,在dom真正render之前,React中的调度机制可能会不定期的去查看有没有更高优先级的任务,如果有,就打断当前的周期执行函数(哪怕已经执行了一半),等高优先级任务完成,再回来重新执行之前被打断的周期函数。这种新机制对现存周期函数的影响就是它们的调用时机变的复杂而不可预测,这也就是为什么”UNSAFE”。
---------------------
作者:辰辰沉沉大辰沉
来源:CSDN
原文:https://blog.csdn.net/Napoleonxxx/article/details/81120854
什么是大循环?
即执行某个fiber后, 会执行他的子元素, 如果没有子元素, 则兄弟元素, 然后又回到父元素, 父兄弟元素...
而寻找元素则是根据其上面几个属性return(父元素),child(子元素),sibiling(兄弟元素)
假设有以下的代码:
<div>
<span1></span1>
<p>
<span2><span2>
</p>
</div>
他的执行如图
Fiber的优先级?
再下来, fiber又是怎么做到根据优先级执行任务时不会卡顿呢,如果任务很多, 无穷无尽, 那不是一样会丢帧?
这时候就是requestIdleCallback这个API的骚操作了, 这个API是干嘛的呢?
window.requestIdleCallback()
会在浏览器空闲时期依次调用函数, 这就可以让开发者在主事件循环中执行后台或低优先级的任务,而且不会对像动画和用户交互这样延迟触发而且关键的事件产生影响。函数一般会按先进先调用的顺序执行,除非函数在浏览器调用它之前就到了它的超时时间。
也就是说React实际上利用这个API在浏览器空闲期执行任务, 而这个API的回调有个参数deadline , 当你超时的时候,无论是不是在空闲期都会执行该任务, 这也就解释了为什么React采用时间来做优先级
不过实际上, React并没有在版本中使用了这个API,而是通过requestAnimationFrame来hack,强行设置每一帧的到期时间为requestAnimationFrame回调函数的参数加上33ms
var animationTick = function (rafTime) {
isAnimationFrameScheduled = false;
...
...
// 每帧到期时间为33ms
frameDeadline = rafTime + 33
if (!isIdleScheduled) {
isIdleScheduled = true;
window.postMessage(messageKey, '*');
}
};
当然了, 分优先级是有一个无法避免的问题, 那就是当有无数的优先级更高的任务插进来, 就会形成饥饿现象,原有的任务会一直得不到机会执行
后面还有一个打了注释Effect标签的几个属性,这几个属性主要是收集每次更新的结果, 并在最后一层层往上迭代, 最后由最高的节点收集, 并执行更新。
在分析的过程中,发现了React的源码中使用了很多链式结构, 回调链,任务链等, 这个主要是为了增删时性能比较高
最后总结一下:
React Fiber实际上就是一个任务调和器,它做到了将每一次更新切分成任务分片,从而拥有了可中断且有优先级的进行其他任务的功能。
如果想看源码, 可以参考本系列的另外三篇文章
React Fiber源码分析 第一篇
React Fiber源码分析 第二篇(同步模式)
React Fiber源码分析 第三篇(异步状态)
React Fiber源码分析 (介绍)的更多相关文章
- React Fiber源码分析 第二篇(同步模式)
先附上两张流程图 1.scheduleRootUpdate 这个函数主要执行了两个操作 1个是创建更新createUpdate并放到更新队列enqueueUpdate, 1个是执行sheculeW ...
- React Fiber源码分析 第一篇
先附上流程图一张 先由babel编译, 调用reactDOM.render,入参为element, container, callback, 打印出来可以看到element,container,cal ...
- React Fiber源码分析 第三篇(异步状态)
先附上流程图~ 调用setState时, 会调用classComponentUpdater的enqueueSetState方法, 同时将新的state作为payload参数传进 enqueueSetS ...
- MyBatis 源码分析——介绍
笔者第一次接触跟MyBatis框架是在2009年未的时候.不过那个时候的他并不叫MyBatis,而是叫IBatis.2010年的时候改为现在的名字--MyBatis.这几年过去了,对于笔者来讲有一点陌 ...
- Java技术开发专题系列之【Guava RateLimiter】针对于限流器的入门到精通(针对于源码分析介绍)
Guava包中限流实现分析 RateLimiter 之前的文章中已经介绍了常用的限流算法,而google在Java领域中使用Guava包中的限流工具进行服务限流. 回顾使用案例 Google开源工具包 ...
- libevent源码分析-介绍、安装、使用
Libevent介绍 安装 样例 Libevent介绍 在include\event2\event.h中有关于Libevent的介绍,这里简单翻译介绍一下: Libevent是以事件为驱动的开发可扩展 ...
- 深入理解 spring 容器,源码分析加载过程
Spring框架提供了构建Web应用程序的全功能MVC模块,叫Spring MVC,通过Spring Core+Spring MVC即可搭建一套稳定的Java Web项目.本文通过Spring MVC ...
- 集合源码分析[3]-ArrayList 源码分析
历史文章: Collection 源码分析 AbstractList 源码分析 介绍 ArrayList是一个数组队列,相当于动态数组,与Java的数组对比,他的容量可以动态改变. 继承关系 Arra ...
- MapReduce源码分析之LocatedFileStatusFetcher
LocatedFileStatusFetcher是MapReduce中一个针对给定输入路径数组,使用配置的线程数目来获取数据块位置的实用类.它的主要作用就是利用多线程技术,每个线程对应一个任务,每个任 ...
随机推荐
- Linux系统下,在文件中查找某个字符串
在normal模式下按下/即可进入查找模式,输入要查找的字符串并按下回车. Vim会跳转到第一个匹配.按下n查找下一个,按下N查找上一个. Vim查找支持正则表达式,例如/vim$匹配行尾的" ...
- Cheat Engine 6.8 设置中文
下载翻译文件包 https://cheatengine.org/downloads.php 下载后解压到 "Cheat Engine 6.8.3\languages" 下面 修改 ...
- 如何理解opencv, python-opencv 和 libopencv?
转: OpenCV is a computer vision library written using highly optimized C/C++ code. It makes use of ...
- webpack配置非CMD规范的模块
一.前言 webpack在配置多页面开发的时候 ,发现用 import 导入 Zepto 时,会报 Uncaught TypeError: Cannot read property 'createEl ...
- python语法_json_pickle
---恢复内容开始--- dic = {"name":"kevin","age":"20"} f = open(&quo ...
- DB2 数据库的安装配置及监控
一.DB2简介 IBM公司研制的一种关系型数据库系统.DB2主要应用于大型应用系统,具有较好的可伸缩性,可支持从大型机到单用户环境,应用于OS/2.Windows等平台下. DB2提供了高层次的数据利 ...
- FCC(ES6写法) Friendly Date Ranges
把常见的日期格式如:YYYY-MM-DD 转换成一种更易读的格式. 易读格式应该是用月份名称代替月份数字,用序数词代替数字来表示天 (1st 代替 1). 包含当前年份和相同月份的时候,makeFri ...
- 简述一下MVC和MVVM
一. MVC 我们先来了解一下什么是MVC. MVC:分别所指Model.View.Controller. MVC为标准的设计模式,是官方推荐的权威的规范模式. 视图(View):用户交互界面. 控制 ...
- LeetCode题解38.Count and Say
38. Count and Say The count-and-say sequence is the sequence of integers beginning as follows: 1, 11 ...
- Animator 动画第一次播放正常,之后播放都不正常的问题解决
Animator 动画第一次播放正常,之后播放都不正常的问题解决 问题描述 第一次点击图片动画播放正常,在点击文字之后,图片没有显示出来,点击空白,播放动画,显示文字. 写了一个卡片翻转的动画,代码如 ...