面试官:你是怎样理解Fiber的
hello,这里是潇晨,今天我们来聊一聊Fiber。不知道大家面试的时候有没有遇到过和react Fiber相关的问题呢,这一类问题比较开放,但也是考察对react源码理解深度的问题,如果面试高级前端岗,恰巧你平时用的是react,那这道面试题是你必需要会的一道。
大型应用为什么会慢
那之前的应用为什么会慢呢,传统的前端应用例如js原生或者jquery应用,在构建复杂的大型应用的时候,各种页面之前的相互操作和更新很有可能会引起页面的重绘或重排列,而频繁操作这些dom其实是非常消耗性能的

在看下图,这是一个节点上的属性,可以看到一个节点上的属性是非常多的,在复杂应用中,操作这些属性的时候可能一不小心就会引起节点大量的更新,那如何提高应用的性能呢?
const div = document.createElement('div');
let str = ''
for(let k in div){str+=','+k
}
console.log(str)

为什么会出现Fiber
react从15版本开始,到现在的17,以及快出来的18,内部经历了非常大的变化,这一切都是围绕着一个目标进行的,这个目标是异步可中断的更新,而这个目的的最终结果是为了构建快速响应的应用。
复杂应用在更新的时候可能会更新大量的dom,所以react在应用层和dom层之间增加了一层Fiber,而Fiber是在内存中工作的,所以在更新的时候只需要在内存中进行dom更新的比较,最后再应用到需要更新真实节点上
这就引出了一个对比新老节点的过程,而对比两棵树的计算其实是非常消耗性能的,react提出了diff算法来降低对比的复杂度,具体diff的过程可以参考往期文章 diff算法
但是面对越来越复杂的应用,diff算法消耗的时间片还是很长,在没做出优化的情况下,react在进行Fiber的对比和更新节点上的状态的时候依然力不从心,
- 在react15之前,这个对比的过程被称之为stack reconcile,它的对比方式是‘一条路走到黑’,也就是说这个对比的过程是不能被中断的,这会出现什么情况呢,比如在页面渲染一个比较消耗性能操作,如果这个时候如果用户进行一些操作就会出现卡顿,应用就会显得不流畅。
- react16之后出现了scheduler,以及react17的Lane模型,它们可以配合着工作,将比较耗时的任务按照Fiber节点划分成工作单元,并且遍历Fiber树计算或者更新节点上的状态可以被中断、继续,以及可以被高优先级的任务打断,比如用户触发的更新就是一个高优先级的任务,高优先级的任务优先执行,应用就不会太卡顿。
什么是Fiber
这就是react所要做的事情了,react创新的提出了jsx,声明式地描述页面呈现的效果,jsx会被babel经过ast解析成React.createElement,而React.createElement函数执行之后就是jsx对象或者说是virtual-dom
- 在mount的时候,也就是首次渲染的时候,render阶段会根据jsx对象生成新的Fiber节点,然后这些Fiber节点会被标记成带有‘Placement’的副作用,说明它们是新增的节点,需要被插入到真实节点中,在commit阶段就会操作真实节点,将它们插入到dom树中。
- 在update的时候,也就是应用触发更新的时候,render阶段会根据最新的jsx和老的Fiber进行对比,生成新的Fiber,这些Fiber会带有各种副作用,比如‘Deletion’、‘Update’、‘Placement’等,这一个对比的过程就是diff算法 ,在commit阶段会操作真实节点,执行相应的副作用。
如果对render阶段和commit阶段不了解的可以查看往期文章
8.render阶段
10.commit阶段

Fiber有比较多的含义,他可以从以下几个角度理解:
-
工作单元 任务分解 :Fiber最重要的功能就是作为工作单元,保存原生节点或者组件节点对应信息(包括优先级),这些节点通过指针的形似形成Fiber树
-
增量渲染:通过jsx对象和current Fiber的对比,生成最小的差异补丁,应用到真实节点上
-
根据优先级暂停、继续、排列优先级:Fiber节点上保存了优先级,能通过不同节点优先级的对比,达到任务的暂停、继续、排列优先级等能力,也为上层实现批量更新、Suspense提供了基础
-
**保存状态:**因为Fiber能保存状态和更新的信息,所以就能实现函数组件的状态更新,也就是hooks
相关参考视频讲解:进入学习
Fiber的数据结构
Fiber的自带的属性如下:
//ReactFiber.old.js
function FiberNode(tag: WorkTag,pendingProps: mixed,key: null | string,mode: TypeOfMode,
) {//作为静态的数据结构 保存节点的信息 this.tag = tag;//对应组件的类型this.key = key;//key属性this.elementType = null;//元素类型this.type = null;//func或者classthis.stateNode = null;//真实dom节点//作为fiber数架构 连接成fiber树this.return = null;//指向父节点this.child = null;//指向childthis.sibling = null;//指向兄弟节点this.index = 0;this.ref = null;//用作为工作单元 来计算statethis.pendingProps = pendingProps;this.memoizedProps = null;this.updateQueue = null;this.memoizedState = null;this.dependencies = null;this.mode = mode;//effect相关this.effectTag = NoEffect;this.nextEffect = null;this.firstEffect = null;this.lastEffect = null;//优先级相关的属性this.lanes = NoLanes;this.childLanes = NoLanes;//current和workInProgress的指针this.alternate = null;
}
Fiber是怎样工作的
现在我们知道了Fiber可以保存真实的dom,真实dom对应在内存中的Fiber节点会形成Fiber树,这颗Fiber树在react中叫current Fiber,也就是当前dom树对应的Fiber树,而正在构建Fiber树叫workInProgress Fiber,这两颗树的节点通过alternate相连.
function App() {return (<><h1><p>count</p> xiaochen</h1></>)
}ReactDOM.render(<App />, document.getElementById("root"));

构建workInProgress Fiber发生在createWorkInProgress中,它能创建或者服用Fiber
//ReactFiber.old.js
export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {let workInProgress = current.alternate;if (workInProgress === null) {//区分是在mount时还是在update时workInProgress = createFiber(current.tag,pendingProps,current.key,current.mode,);workInProgress.elementType = current.elementType;workInProgress.type = current.type;workInProgress.stateNode = current.stateNode;workInProgress.alternate = current;current.alternate = workInProgress;} else {workInProgress.pendingProps = pendingProps;//复用属性workInProgress.type = current.type;workInProgress.flags = NoFlags;workInProgress.nextEffect = null;workInProgress.firstEffect = null;workInProgress.lastEffect = null;//...}workInProgress.childLanes = current.childLanes;//复用属性workInProgress.lanes = current.lanes;workInProgress.child = current.child;workInProgress.memoizedProps = current.memoizedProps;workInProgress.memoizedState = current.memoizedState;workInProgress.updateQueue = current.updateQueue;const currentDependencies = current.dependencies;workInProgress.dependencies =currentDependencies === null? null: {lanes: currentDependencies.lanes,firstContext: currentDependencies.firstContext,};workInProgress.sibling = current.sibling;workInProgress.index = current.index;workInProgress.ref = current.ref;return workInProgress;
}
-
在mount时:会创建fiberRoot和rootFiber,然后根据jsx对象创建Fiber节点,节点连接成current Fiber树。

-
在update时:会根据新的状态形成的jsx(ClassComponent的render或者FuncComponent的返回值)和current Fiber对比形(diff算法)成一颗叫workInProgress的Fiber树,然后将fiberRoot的current指向workInProgress树,此时workInProgress就变成了current Fiber。fiberRoot:指整个应用的根节点,只存在一个
fiberRoot:指整个应用的根节点,只存在一个
rootFiber:ReactDOM.render或者ReactDOM.unstable_createRoot创建出来的应用的节点,可以存在多个。
我们现在知道了存在current Fiber和workInProgress Fiber两颗Fiber树,Fiber双缓存指的就是,在经过reconcile(diff)形成了新的workInProgress Fiber然后将workInProgress Fiber切换成current Fiber应用到真实dom中,存在双Fiber的好处是在内存中形成视图的描述,在最后应用到dom中,减少了对dom的操作。
现在来看看Fiber双缓存创建的过程图:
-
mount时:
- 刚开始只创建了fiberRoot和rootFiber两个节点

- 然后根据jsx创建workInProgress Fiber:

- 把workInProgress Fiber切换成current Fiber

- 刚开始只创建了fiberRoot和rootFiber两个节点
-
update时
- 根据current Fiber创建workInProgress Fiber

- 把workInProgress Fiber切换成current Fiber
- 根据current Fiber创建workInProgress Fiber

为什么Fiber能提升效率
Fiber是一个js对象,能承载节点信息、优先级、updateQueue,同时它还是一个工作单元。
- Fiber双缓存可以在构建好wip Fiber树之后切换成current Fiber,内存中直接一次性切换,提高了性能
- Fiber的存在使异步可中断的更新成为了可能,作为工作单元,可以在时间片内执行工作,没时间了交还执行权给浏览器,下次时间片继续执行之前暂停之后返回的Fiber
- Fiber可以在reconcile的时候进行相应的diff更新,让最后的更新应用在真实节点上
相关文章:
面试官:你是怎样理解Fiber的
hello,这里是潇晨,今天我们来聊一聊Fiber。不知道大家面试的时候有没有遇到过和react Fiber相关的问题呢,这一类问题比较开放,但也是考察对react源码理解深度的问题,如果面试高级前端岗,恰巧你平时用的是re…...
【C++的OpenCV】第一课-opencv的介绍和安装(Linux环境下)
第一课-目录一、基本介绍1.1 官网1.2 git源码1.3 介绍二、OpenCV的相关部署工作2.1 Linux平台下部署OpenCV一、基本介绍 1.1 官网 opencv官网 注意:官网为英文版本,可以使用浏览器自带的翻译插件进行翻译,真心不推荐大家去看别人翻译的&am…...
k8s安装tekton,编写task
文章目录一、官方安装二、国内资源安装安装tekton安装dashboard安装CLI三、demo编写task.yaml编写taskRun.yaml使用tkn命令查看参考文章一、官方安装 地址:https://tekton.dev/docs/installation/pipelines/#installing-tekton-pipelines-on-kubernetes 注意&#…...
K_A12_014 基于STM32等单片机驱动S12SD紫外线传感器模块 串口与OLED0.96双显示
K_A12_014 基于STM32等单片机驱动S12SD紫外线传感器模块 串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:数据对比:四、部分代码说明1、接线引脚定义1.1、STC89C52RCS12SD紫外线传感器模块1.2、STM32F103…...
还真不错,今天 Chatgpt 教会我如何开发一款小工具开发(Python 代码实现)
上次使用 Chatgpt 写爬虫,虽然写出来的代码很多需要修改后才能运行,但Chatgpt提供的思路和框架都是没问题。 这次让 Chatgpt 写一写GUI程序,也就是你常看到的桌面图形程序。 由于第一次测试,就来个简单点的,用Python…...
Boom 3D最新版本下载电脑音频增强应用工具
为了更好地感受音乐的魅力,Boom 3D 可以让你对音效进行个性化增强,并集成 3D 环绕立体声效果,可以让你在使用任何耳机时,都拥有纯正、优质的音乐体验。Boom 3D是一款充满神奇魅力的3D环绕音效升级版,BOOM 3D是一个全新…...
redis-如何保证数据库和缓存双写一致性?
前言 数据库和缓存(比如:redis)双写数据一致性问题,是一个跟开发语言无关的公共问题。尤其在高并发的场景下,这个问题变得更加严重。 我很负责的告诉大家,该问题无论在面试,还是工作中遇到的概率…...
系列二、核心概念运行流程
一、镜像&容器&仓库 1.1、镜像 定义:一个镜像代表着一个软件,例如:mysql镜像、redis镜像、nginx镜像。 特点:只读 1.2、容器 定义:基于某个镜像运行一次就会生成一个程序实例,一个程序实例称之为一…...
恢复 iPhone 和 iPad 数据的 10 种简单工具
它发生了.. 有时您需要从您的手机或平板设备恢复重要数据。 许多人已经开始将重要文件存储在手机上,因为他们几乎可以在任何情况下随时随地轻松访问数据。 从技术上讲,您会在几分之一秒内丢失所有存储的信息、照片、视频、音乐、文档等。因此ÿ…...
经理与员工工资关系-课后程序(JAVA基础案例教程-黑马程序员编著-第四章-课后作业)
【案例4-6】经理与员工工资案例(利用多态实现) 欢迎点赞关注收藏 【案例介绍】 案例描述 某公司的人员分为员工和经理两种,但经理也属于员工中的一种,公司的人员都有自己的姓名和地址,员工和经理都有自己的工号、工…...
Micropython ESP32配置与烧录版本
下载ESP32的Micropython固件 官方连接https://www.micropython.org/download/esp32/ 看了下描述,上面的是IDF4.x系列编译,下面是IDF3.x系列编译,我们默认选新的 下载安装CP2102驱动 CP210x USB to UART Bridge VCP Drivers - Silicon Labs…...
java面试题-并发关键字(Synchronized,volatile,final)
Synchronized1.Synchronized可以作用在哪里?Synchronized可以作用在方法、代码块、静态方法和类上。方法public synchronized void method(){//同步代码块 }代码块Object lock new Object(); synchronized(lock){//同步代码块 }静态方法public static synchronized void stat…...
【笔试强训】Day_02
目录 一、选择题 1、 2、 3、 4、 5、 6、 7、 8、 9、 10、 二、编程题 1、排序子序列 2、倒置字符串 一、选择题 1、 使用printf函数打印一个double类型的数据,要求:输出为10进制,输出左对齐30个字符,4位精度。…...
DepGraph:适用任何结构的剪枝
文章目录摘要1、简介2、相关工作3、方法3.1、神经网络中的依赖关系3.2、依赖关系图3.3、使用依赖图剪枝4、实验4.1、设置。4.2、CIFAR的结果4.3、消融实验4.4、适用任何结构剪枝5、结论摘要 论文链接:https://arxiv.org/abs/2301.12900 源码:https://gi…...
【结构体版】通讯录
👦个人主页:Weraphael ✍🏻作者简介:目前是C语言学习者 ✈️专栏:项目 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞&#x…...
Debezium系列之:基于debezium采集数据到kafka,再从kafka将数据流式传输到下游数据库
Debezium系列之:基于debezium采集数据到kafka,再从kafka将数据流式传输到下游数据库 一、需求背景二、准备Debezium集群和相关jar包的详细步骤三、查看插件是否加载成功四、源数据库表结构五、根据源数据库表结构准备目标数据库的表六、基于debezium采集数据到kafka七、查看c…...
【2023】华为OD机试真题Java-题目0217-上班之路
上班之路 题目描述 Jungle生活在美丽的蓝鲸城,大马路都是方方正正,但是每天马路的封闭情况都不一样。 地图由以下元素组成: . — 空地,可以达到;* — 路障,不可达到;S — Jungle的家;T — 公司. 其中我们会限制Jungle拐弯的次数,同时Jungle可以清除给定个数的路障,现在…...
基于spring生态的基础后端开发及渗透测试流程(二)
基于spring生态的基础后端开发及渗透测试流程(二)安全设备IDS蜜罐安全加固渗透测试信息收集子域名域名注册信息企业信息端口扫描源码泄露路径扫描真实ip探测js扫描设备检测蜜罐识别waf识别社工爆破漏洞扫描系统扫描web扫描应急响应继上次写了一份基于spr…...
Python语言零基础入门教程(二十六)
Python OS 文件/目录方法 Python语言零基础入门教程(二十五) 51、Python os.stat_float_times() 方法 概述 os.stat_float_times() 方法用于决定stat_result是否以float对象显示时间戳。 语法 stat_float_times()方法语法格式如下: os.s…...
人们最想看到的是:你在坚持什么?
【人们最想看到的是:你在坚持什么】 长远规划才能对抗不确定性 品牌也能够对抗不确定性 想想这么多年东搞搞,西搞搞 最后缺乏正向积累的【厚度】 趣讲大白话:把每滴水尽量接到碗里 人吃的是饭,拉出来的是信息 *********** 人们在频…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
