reactFiberLane
Lane (车道模型)
英文单词
lane翻译成中文表示"车道, 航道"的意思, 所以很多文章都将Lanes模型称为车道模型
Lane模型的源码在ReactFiberLane.js, 源码中大量使用了位运算(有关位运算的讲解,
首先引入作者对Lane的解释(相应的 pr), 这里简单概括如下:
Lane类型被定义为二进制变量, 利用了位掩码的特性, 在频繁运算的时候占用内存少, 计算速度快.Lane和Lanes就是单数和复数的关系, 代表单个任务的定义为Lane, 代表多个任务的定义为Lanes
Lane是对于expirationTime的重构, 以前使用expirationTime表示的字段, 都改为了lane
renderExpirationtime -> renderLanesupdate.expirationTime -> update.lanefiber.expirationTime -> fiber.lanesfiber.childExpirationTime -> fiber.childLanesroot.firstPendingTime and root.lastPendingTime -> fiber.pendingLanes
- 使用
Lanes模型相比expirationTime模型的优势: Lanes把任务优先级从批量任务中分离出来, 可以更方便的判断单个任务与批量任务的优先级是否重叠.
// 判断: 单task与batchTask的优先级是否重叠
//1. 通过expirationTime判断
const isTaskIncludedInBatch = priorityOfTask >= priorityOfBatch;
//2. 通过Lanes判断
const isTaskIncludedInBatch = (task & batchOfTasks) !== 0;// 当同时处理一组任务, 该组内有多个任务, 且每个任务的优先级不一致
// 1. 如果通过expirationTime判断. 需要维护一个范围(在Lane重构之前, 源码中就是这样比较的)
const isTaskIncludedInBatch =taskPriority <= highestPriorityInRange &&taskPriority >= lowestPriorityInRange;
//2. 通过Lanes判断
const isTaskIncludedInBatch = (task & batchOfTasks) !== 0;
Lanes使用单个 32 位二进制变量即可代表多个不同的任务, 也就是说一个变量即可代表一个组(group), 如果要在一个 group 中分离出单个 task, 非常容易.
在
expirationTime模型设计之初, react 体系中还没有Suspense 异步渲染的概念. 现在有如下场景: 有 3 个任务, 其优先级A > B > C, 正常来讲只需要按照优先级顺序执行就可以了. 但是现在情况变了: A 和 C 任务是CPU密集型, 而 B 是IO密集型(Suspense 会调用远程 api, 算是 IO 任务), 即A(cpu) > B(IO) > C(cpu). 此时的需求需要将任务B从 group 中分离出来, 先处理 cpu 任务A和C.
// 从group中删除或增加task//1. 通过expirationTime实现
// 0) 维护一个链表, 按照单个task的优先级顺序进行插入
// 1) 删除单个task(从链表中删除一个元素)
task.prev.next = task.next;
// 2) 增加单个task(需要对比当前task的优先级, 插入到链表正确的位置上)
let current = queue;
while (task.expirationTime >= current.expirationTime) {current = current.next;
}
task.next = current.next;
current.next = task;
// 3) 比较task是否在group中
const isTaskIncludedInBatch =taskPriority <= highestPriorityInRange &&taskPriority >= lowestPriorityInRange;// 2. 通过Lanes实现
// 1) 删除单个task
batchOfTasks &= ~task;
// 2) 增加单个task
batchOfTasks |= task;
// 3) 比较task是否在group中
const isTaskIncludedInBatch = (task & batchOfTasks) !== 0;
Lanes是一个不透明的类型, 只能在ReactFiberLane.js这个模块中维护. 如果要在其他文件中使用, 只能通过ReactFiberLane.js中提供的工具函数来使用.
分析车道模型的源码(ReactFiberLane.js中), 可以得到如下结论:
- 可以使用的比特位一共有 31 位
- 共定义了18 种车道(Lane/Lanes)变量, 每一个变量占有 1 个或多个比特位, 分别定义为
Lane和Lanes类型. - 每一种车道(
Lane/Lanes)都有对应的优先级, 所以源码中定义了 18 种优先级(LanePriority). - 占有低位比特位的
Lane变量对应的优先级越高- 最高优先级为
SyncLanePriority对应的车道为SyncLane = 0b0000000000000000000000000000001. - 最低优先级为
OffscreenLanePriority对应的车道为OffscreenLane = 0b1000000000000000000000000000000.
- 最高优先级为
位运算
什么是位运算? 程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。
比如
- 0 在二进制中用 0 表示,我们用 0000 代表;
- 1 在二进制中用 1 表示,我们用 0001 代表;
那么先看两个位元算符号 & 和 |:
- & 对于每一个比特位,两个操作数都为 1 时, 结果为 1, 否则为 0
- | 对于每一个比特位,两个操作数都为 0 时, 结果为 0, 否则为 1
我们看一下两个 1 & 0 和 1 | 0
如上 1 & 0 = 0 ,1 | 0 = 1


位运算的一个使用场景:
比如有一个场景下,会有很多状态常量 A,B,C…,这些状态在整个应用中在一些关键节点中做流程控制,比如:
if(value === A){ // TODO… }
如上判断 value 等于常量A ,那么进入到 if 的条件语句中。 此时是 value 属性是简单的一对一关系,但是实际场景下 value 可能是好几个枚举常量的集合,也就是一对多的关系,那么此时 value 可能同时代表 A 和 B 两个属性。如下图所示:

此时的问题就是如何用一个 value 表示 A 和 B 两个属性的集合。 这个时候位运算就派上用场了,因为可以把一些状态常量用 32 位的二进制来表示(这里也可以用其他进制),比如:
const A = 0b0000000000000000000000000000001
const B = 0b0000000000000000000000000000010
const C = 0b0000000000000000000000000000100
通过移位的方式让每一个常量都单独占一位,这样在判断一个属性是否包含常量的时候,可以根据当前位数的 1 和 0 来判断。
这样如果一个值即代表 A 又代表 B 那么就可以通过位运算的 | 来处理。就有
AB = A | B = 0b0000000000000000000000000000011
那么如果把 AB 的值赋予给 value ,那么此时的 value 就可以用来代表 A 和 B 。
此时当然不能直接通过等于或者恒等来判断 value 是否为 A 或者 B ,此时就可以通过 & 来判断。具体实现如下:
const A = 0b0000000000000000000000000000001
const B = 0b0000000000000000000000000000010
const C = 0b0000000000000000000000000000100
const N = 0b0000000000000000000000000000000
const value = A | B
console.log((value & A ) !== N ) // true
console.log((value & B ) !== N ) // true
console.log((value & C ) !== N ) // false
位运算在react中的运用
export const NoLanes = /* */ 0b0000000000000000000000000000000;
const SyncLane = /* */ 0b0000000000000000000000000000001;const InputContinuousHydrationLane = /* */ 0b0000000000000000000000000000010;
const InputContinuousLane = /* */ 0b0000000000000000000000000000100;const DefaultHydrationLane = /* */ 0b0000000000000000000000000001000;
const DefaultLane = /* */ 0b0000000000000000000000000010000;const TransitionHydrationLane = /* */ 0b0000000000000000000000000100000;
const TransitionLane = /* */ 0b0000000000000000000000001000000;
如上 SyncLane 代表的数值是 1,它却是最高的优先级,也即是说 lane 的代表的数值越小,此次更新的优先级就越大 ,在新版本的 React 中,还有一个新特性,就是 render 阶段可能被中断,在这个期间会产生一个更高优先级的任务,那么会再次更新 lane 属性,这样多个更新就会合并,这样一个 lane 可能需要表现出多个更新优先级。
我们来看一下 React 是如何通过位运算分离出优先级的。
function getHighestPriorityLane(lanes) {return lanes & -lanes;
}
如上就是通过 lanes & -lanes 分离出最高优先级的任务的,我们来看一下具体的流程。
比如 SyncLane 和 InputContinuousLane 合并之后的任务优先级 lane 为
SyncLane = 0b0000000000000000000000000000001 InputContinuousLane = 0b0000000000000000000000000000100
lane = SyncLane | InputContinuousLane lane = 0b0000000000000000000000000000101
那么通过 lanes & -lanes 分离出 SyncLane。
首先我们看一下 -lanes,在二进制中需要用补码表示为:
-lane = 0b1111111111111111111111111111011
那么接下来执行 lanes & -lanes 看一下,& 的逻辑是如果两位都是 1 则设置改位为 1,否则为 0。
那么 lane & -lane ,只有一位(最后一位)全是 1,所有合并后的内容为:
lane & -lane = 0b0000000000000000000000000000001
可以看得出来 lane & -lane 的结果是 SyncLane,所以通过 lane & -lane 就能分离出最高优先级的任务。
const SyncLane = 0b0000000000000000000000000000001
const InputContinuousLane = 0b0000000000000000000000000000100
const lane = SyncLane | InputContinuousLane
console.log( (lane & -lane) === SyncLane ) // true
优先级区别和联系
在源码中, 3 种优先级位于不同的 js 文件, 是相互独立的.
注意:
LanePriority和SchedulerPriority从命名上看, 它们代表的是优先级ReactPriorityLevel从命名上看, 它代表的是等级而不是优先级, 它用于衡量LanePriority和SchedulerPriority的等级.
LanePriority
LanePriority`: 属于`react-reconciler`包, 定义于`ReactFiberLane.js
export const SyncLanePriority: LanePriority = 15;
export const SyncBatchedLanePriority: LanePriority = 14;const InputDiscreteHydrationLanePriority: LanePriority = 13;
export const InputDiscreteLanePriority: LanePriority = 12;// .....const OffscreenLanePriority: LanePriority = 1;
export const NoLanePriority: LanePriority = 0;
与fiber构造过程相关的优先级(如fiber.updateQueue,fiber.lanes)都使用LanePriority.
由于本节重点介绍优先级体系以及它们的转换关系, 关于Lane(车道模型)在fiber树构造时的具体使用, 在fiber 树构造章节详细解读.
SchedulerPriority
SchedulerPriority, 属于scheduler包, 定义于SchedulerPriorities.js中
export const NoPriority = 0;
export const ImmediatePriority = 1;
export const UserBlockingPriority = 2;
export const NormalPriority = 3;
export const LowPriority = 4;
export const IdlePriority = 5;
与scheduler调度中心相关的优先级使用SchedulerPriority.
ReactPriorityLevel
reactPriorityLevel, 属于react-reconciler包, 定义于SchedulerWithReactIntegration.js中
export const ImmediatePriority: ReactPriorityLevel = 99;
export const UserBlockingPriority: ReactPriorityLevel = 98;
export const NormalPriority: ReactPriorityLevel = 97;
export const LowPriority: ReactPriorityLevel = 96;
export const IdlePriority: ReactPriorityLevel = 95;
// NoPriority is the absence of priority. Also React-only.
export const NoPriority: ReactPriorityLevel = 90;
LanePriority与SchedulerPriority通过ReactPriorityLevel进行转换
转换关系
为了能协同调度中心(scheduler包)和 fiber 树构造(react-reconciler包)中对优先级的使用, 则需要转换SchedulerPriority和LanePriority, 转换的桥梁正是ReactPriorityLevel.
在SchedulerWithReactIntegration.js中, 可以互转SchedulerPriority 和 ReactPriorityLevel:
// 把 SchedulerPriority 转换成 ReactPriorityLevel
export function getCurrentPriorityLevel(): ReactPriorityLevel {switch (Scheduler_getCurrentPriorityLevel()) {case Scheduler_ImmediatePriority:return ImmediatePriority;case Scheduler_UserBlockingPriority:return UserBlockingPriority;case Scheduler_NormalPriority:return NormalPriority;case Scheduler_LowPriority:return LowPriority;case Scheduler_IdlePriority:return IdlePriority;default:invariant(false, 'Unknown priority level.');}
}// 把 ReactPriorityLevel 转换成 SchedulerPriority
function reactPriorityToSchedulerPriority(reactPriorityLevel) {switch (reactPriorityLevel) {case ImmediatePriority:return Scheduler_ImmediatePriority;case UserBlockingPriority:return Scheduler_UserBlockingPriority;case NormalPriority:return Scheduler_NormalPriority;case LowPriority:return Scheduler_LowPriority;case IdlePriority:return Scheduler_IdlePriority;default:invariant(false, 'Unknown priority level.');}
}
在ReactFiberLane.js中, 可以互转LanePriority 和 ReactPriorityLevel:
export function schedulerPriorityToLanePriority(schedulerPriorityLevel: ReactPriorityLevel,
): LanePriority {switch (schedulerPriorityLevel) {case ImmediateSchedulerPriority:return SyncLanePriority;// ... 省略部分代码default:return NoLanePriority;}
}export function lanePriorityToSchedulerPriority(lanePriority: LanePriority,
): ReactPriorityLevel {switch (lanePriority) {case SyncLanePriority:case SyncBatchedLanePriority:return ImmediateSchedulerPriority;// ... 省略部分代码default:invariant(false,'Invalid update priority: %s. This is a bug in React.',lanePriority,);}
}
优先级使用
通过reconciler运行流程中的归纳, reconciler从输入到输出一共经历了 4 个阶段, 在每个阶段中都会涉及到与优先级相关的处理. 正是通过优先级的灵活运用, React实现了可中断渲染,时间切片(time slicing),异步渲染(suspense)等特性.
突然很后悔当初没有跟老师好好学数电,在此缅怀许院王教授
相关文章:
reactFiberLane
Lane (车道模型) 英文单词lane翻译成中文表示"车道, 航道"的意思, 所以很多文章都将Lanes模型称为车道模型 Lane模型的源码在ReactFiberLane.js, 源码中大量使用了位运算(有关位运算的讲解, 首先引入作者对Lane的解释(相应的 pr), 这里简单概括如下: Lane类型被定义…...
Hackademic.RTB1靶场实战【超详细】
靶机下载链接:https://download.vulnhub.com/hackademic/Hackademic.RTB1.zip 一、主机探测和端口扫描 nmap 192.168.121.0/24 ip:192.168.121.196 端口:22、80 二、访问80端口 发现target可点击 点击后跳转,页面提示目标是读取到 key.txt 文件 fin…...
让3岁小孩都能理解LeetCode每日一题_3148.矩阵中的最大得分
解释说明: 上面的内容的意思是为了有只移动一次的情况,而后面的grid(i,j)-grid(i,k)由于j严格大于k,所以至少移动了一次,前面可以保持不移动,不移动就是选择0。 class Solution {public int maxScore(List<List&l…...
8.15日学习打卡---Spring Cloud Alibaba(三)
8.15日学习打卡 目录: 8.15日学习打卡为什么需要服务网关Higress是什么安装DockerCompose部署Higress创建网关微服务模块Higress路由配置Higress策略配置-跨域配置Higress解决如何允许跨域Higress策略配置之什么是HTTP认证Higress策略配置-Basic 认证什么是JWT认证J…...
2024下半年EI学术会议一览表
2024下半年将举办多个重要的EI学术会议,涵盖了从机器视觉、图像处理与影像技术到感知技术、绿色通信、计算机、大数据与人工智能等多个领域。 2024下半年EI学术会议一览表 第二届机器视觉、图像处理与影像技术国际会议(MVIPIT 2024)将于2024…...
【海奇HC-RTOS平台E100-问题点】
海奇HC-RTOS平台E100-问题点 ■ btn 没有添加到group中 ,怎么实现的事件的■ 屏幕是1280*720, UI是1024*600,是否修改UI■ hc15xx-db-e100-v10-hcdemo.dtb 找不到■ 触摸屏驱动 能否给个实例■ 按键驱动■ __initcall(projector_auto_start)■ source insigt4.0 #if…...
性能测试之Mysql数据库调优
一、前言 性能调优前提:无监控不调优,对于mysql性能的监控前几天有文章提到过,有兴趣的朋友可以去看一下 二、Mysql性能指标及问题分析和定位 1、我们在监控图表中关注的性能指标大概有这么几个:CPU、内存、连接数、io读写时间…...
使用 RestHighLevelClient 进行 Elasticsearch 高亮查询及解析
在搜索引擎中,高亮显示查询关键字是一个提升用户体验的功能,它可以帮助用户更快地定位到相关信息。Elasticsearch 支持在搜索结果中对匹配的文本进行高亮显示。本文将介绍如何在 Java 应用程序中使用 Elasticsearch 的 RestHighLevelClient 执行高亮查询…...
Java基础入门15:算法、正则表达式、异常
算法(选择排序、冒泡排序、二分查找) 选择排序 每轮选择当前位置,开始找出后面的较小值与该位置交换。 选择排序的关键: 确定总共需要选择几轮:数组的长度-1。 控制每轮从以前位置为基准,与后面元素选择…...
SpringBoot响应式编程 WebFlux入门教程
🍁 作者:知识浅谈,CSDN签约讲师,CSDN博客专家,华为云云享专家,阿里云专家博主 📌 擅长领域:全栈工程师、爬虫、ACM算法 🔥 微信:zsqtcyw 联系我领取学习资料 …...
LeetCode 383. 赎金信
题目 给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以,返回 true ;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1: 输入&…...
python绘制电路图
要在 Python 中实现电路图,你可以使用一些专门的库来创建和可视化电路图。一个常用的库是 schemdraw,它可以用来绘制电路图,并支持多种电气组件和符号。 下面是一个使用 schemdraw 库绘制简单电路图的示例: 安装 schemdraw 库&am…...
Vue3 Suspense 和 defineAsyncComponent 结合使用方法
Suspense:用于协调对组件树中嵌套的异步依赖的处理。 defineAsyncComponent:定义一个异步组件,它在运行时是懒加载的。参数可以是一个异步加载函数,或是对加载行为进行更具体定制的一个选项对象。 异步组件的好处:使…...
GitHub中Codespace怎么使用;LLM模拟初始化;MLP:全连接神经网络的并行执行
目录 PyUnit unittest是什么 unittest怎么使用 GitHub中Codespace怎么使用 测试常用功能 LLM模拟初始化 参数解释 类属性设置 总结 MLP:全连接神经网络的并行执行 假设 代码解释 注意事项 PyUnit unittest是什么 unittest是Python的内置单元测试框架,原名PyUn…...
【rh】rh项目部署
【fastadmin】 1、项目先clone到本地,其中web为h5前端使用(gitclone后,把web内容放进去再提交),其余为项目后端使用 2、安装本地环境,项目跑起来,步骤如下: 1)查春.git 和 composer,json 版本信…...
VoxelNet: End-to-End Learning for Point Cloud Based 3D Object Detection
VoxelNet: End-to-End Learning for Point Cloud Based 3D Object Detection Abstract 摘要部分,作者首先指出了3D点云中目标检测的重要性,在自动驾驶导航、家政机器人以及增强现实和虚拟现实等多个领域有重要的作用。然后,提到了现有方法的…...
结构开发笔记(三):solidworks软件(二):小试牛刀,绘制一个立方体
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/141122350 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...
LLM 量化算法AutoRound 0.3 发布及原理浅析
这里写自定义目录标题 AutoRound V0.3 特性原理浅析其他工作AutoRound 原理 AutoRound(https://github.com/intel/auto-round)在Llama3.1-8B-Instruct上效果明显优于AWQ/GPTQ等方法,在10个任务的平均准确率上我们以63.93%由于AWQ的63.15%和GP…...
汽车免拆诊断案例 | 2013款北京现代悦动车发动机偶尔无法起动
故障现象 一辆2013款北京现代悦动车,搭载G4FC发动机,累计行驶里程约为13.9万km。车主反映,发动机偶尔无法起动着机,断开点火开关,等待一会儿又可以起动着机。 故障诊断 接车后反复试车,当发动机无法起动着…...
React、AntD,封装动态表单
在React中使用Ant Design(简称AntD)来封装动态表单是一个常见的需求,特别是在需要灵活配置表单字段的场景下。以下是一个基本的步骤和示例代码,展示如何使用React和AntD来封装一个动态表单。 步骤 1: 安装必要的库 首先,确保你的项目中已经安装了react和antd。如果还没有…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
【笔记】AI Agent 项目 SUNA 部署 之 Docker 构建记录
#工作记录 构建过程记录 Microsoft Windows [Version 10.0.27871.1000] (c) Microsoft Corporation. All rights reserved.(suna-py3.12) F:\PythonProjects\suna>python setup.py --admin███████╗██╗ ██╗███╗ ██╗ █████╗ ██╔════╝…...
