React 第三十八章 React 中的位运算

位运算是一种计算机编程中常用的操作,它直接对二进制位进行操作。二进制,指的就是以二为底的一种计数方式,常见的还有八进制、十进制、十六进制。

十进制0123456789101112131415
二进制0000000100100011010001010110011110001001101010111100110111101111
八进制012345671011121314151617
十六进制0123456789ABCDEF

我们经常会使用二进制来进行计算,基于二进制的位运算能够很方便的表达“增、删、查、改”。

例如一个后台管理系统,一般的话会有针对权限的控制,一般权限的控制就使用的是二进制:

// 各个权限
permissions = {"SYS_SETTING" : {"value" : 0b10000000,"info" : "系统重要设置权限"},"DATA_ADMIN" : {"value" : 0b01000000,"info" : "数据库管理权限"},"USER_MANG" : {"value" : 0b00100000,"info" : "用户管理权限"},"POST_EDIT" : {"value" : 0b00010000,"info" : "文章编辑操作权限"},"POST_VIEW" : {"value" : 0b00001000,"info" : "文章查看权限"}
}

再例如,在 linux 操作系统里面,x 代表可执行权限,w代表可写权限,r 代表可读权限,对应的权限值分别就是1、2、4(2 的幂次方)

使用二进制来表示权限,首先速度上面会更快一些,其次在表示多种权限的时候,会更加方便一些。

比如,现在有 3 个权限 A、B、C…

根据不同的权限做不同的事情:

if(value === A){// ...
} else if(value === B){// ...
}

在上面的代码中,会有一个问题,目前仅仅只是一对一的关系,但是在实际开发中,往往有很多一对多的关系,一个 value 可能会对应好几个值。

image-20230103135329257

二进制相关的运算:

  • 与( & ):只要有一位数为 0,那么最终结果就是 0,也就是说,必须两位都是 1,最终结果才是 1
1 & 1 = 10000 0001
0000 0001
---------
0000 00011 & 0 = 00000 0001
0000 0000
---------
0000 0000
  • 或( | ): 只要有一位数是 1,那么最终结果就是 1,也就是说必须两个都是 0,最终才是 0
1 | 0 = 10000 0001
0000 0000
---------
0000 0001
  • 非 ( ~ ): 对一个二进制数逐位取反,也就是说 0、1 互换
~3
0000 0011
// 逐位取反
1111 1100
// 计算结果最终为 -4(涉及到补码的知识)
  • 异或( ^ ): 如果两个二进制位不相同,那么结果就为 1,相同就为 0
1 ^ 0 = 10000 0001
0000 0000
---------
0000 0001
  • 左移(<<)运算:将一个数的二进制表示向左移动指定的位数,右边补0。
1<<2= 4
0000 0001
// 向左移动2位
0000 0100
  • 右移(>>)运算:将一个数的二进制表示向右移动指定的位数,左边补0或者补符号位(对于有符号数)。
4>>2=1
0000 0100
// 向右移动2位
0000 0001

接下来我们来看一下位运算在权限系统里面的实际运用:

下载打印查看审核详细删除编辑创建
00000000

如果是 0,代表没有权限,如果是 1,代表有权限

0000 0001 代表只有创建的权限,0010 0011 代表有查看、编辑以及创建的权限

添加权限

直接使用或运算即可。

0000 0011 目前有创建和编辑的权限,我们要给他添加一个查看的权限 0010 0000

0000 0011
0010 0000
---------
0010 0011

删除权限

可以使用异或

0010 0011 目前有查看、编辑和创建,取消编辑的权限 0000 0010

0010 0011
0000 0010
---------
0010 0001

判断是否有某一个权限

可以使用与来进行判断

0011 1100(查看、审核、详细、删除),判断是否有查看(0010 0000)权限、再判断是否有创建(0000 0001)权限

0011 1100
0010 0000
---------
0010 0000// 判断是否有“查看”权限,做与操作时得到了“查看”权限值本身,说明有这个权限
0011 1100
0000 0001
---------
0000 0000// 最终得到的值为 0,说明没有此权限

通过上面的例子,我们会发现使用位运算确确实实非常的方便,接下来我们就来看一下 React 中针对位运算的使用。

React 中的位运算

  • fiber 的 flags
  • lane 模型
  • 上下文

fiber 的 flags

在 React 中,用来标记 fiber 操作的 flags,使用的就是二进制:

export const NoFlags = /*                      */ 0b000000000000000000000000000;
export const PerformedWork = /*                */ 0b000000000000000000000000001;
export const Placement = /*                    */ 0b000000000000000000000000010;
export const DidCapture = /*                   */ 0b000000000000000000010000000;
export const Hydrating = /*                    */ 0b000000000000001000000000000;
// ...

这些 flags 就是用来标记 fiber 状态的。

之所以要专门抽离 fiber 的状态,是因为这种操作是非常高效的。针对一个 fiber 的操作,可能有增加、删除、修改,但是我不直接进行操作,而是给这个 fiber 打上一个 flag,接下来在后面的流程中针对有 flag 的 fiber 统一进行操作。

通过位运算,就可以很好的解决一个 fiber 有多个 flag 标记的问题,方便合并多个状态

// 初始化一些 flags
const NoFlags = 0b00000000000000000000000000;
const PerformedWork =0b00000000000000000000000001;
const Placement =  0b00000000000000000000000010;
const Update = 0b00000000000000000000000100;// 一开始将 flag 变量初始化为没有 flag,也就是 NoFlags
let flag = NoFlags// 这里就是在合并多个状态
flag = flag | PerformedWork | Update// 要判断是否有某一个 flag,直接通过 & 来进行判断即可
//判断是否有  PerformedWork 种类的更新
if(flag & PerformedWork){//执行console.log('执行 PerformedWork')
}//判断是否有 Update 种类的更新
if(flag & Update){//执行console.log('执行 Update')
}if(flag & Placement){//不执行console.log('执行 Placement')
}

lane 模型

lane 模型也是一套优先级机制,相比 Scheduler,lane 模型能够对任务进行更细粒度的控制。

export const NoLanes: Lanes = /*                        */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /*                          */ 0b0000000000000000000000000000000;export const SyncLane: Lane = /*                        */ 0b0000000000000000000000000000001;export const InputContinuousHydrationLane: Lane = /*    */ 0b0000000000000000000000000000010;
export const InputContinuousLane: Lane = /*             */ 0b0000000000000000000000000000100;
// ...

例如在 React 源码中,有一段如下的代码:

// lanes 一套 lane 的组合
function getHighestPriorityLanes(lanes) {// 从 lanes 这一套组合中,分离出优先级最高的 laneswitch (getHighestPriorityLane(lanes)) {case SyncLane:return SyncLane;case InputContinuousHydrationLane:return InputContinuousHydrationLane;case InputContinuousLane:return InputContinuousLane;// ...return lanes;}
}// lane 在表示优先级的时候,大致是这样的:
// 0000 0001
// 0000 0010
// 0010 0000
// lanes 表示一套 lane 的组合,比如上面的三个 lane 组合到一起就变成了一个 lanes 0010 0011
// getHighestPriorityLane 这个方法要做的事情就是分离出优先级最高的
// 0010 0011 ----> getHighestPriorityLane -----> 0000 0001export function getHighestPriorityLane(lanes) {return lanes & -lanes;
}

假设现在我们针对两个 lane 进行合并

const SyncLane: Lane = /*                        */ 0b0000000000000000000000000000001;
const InputContinuousLane: Lane = /*             */ 0b0000000000000000000000000000100;

合并出来就是一个 lanes,合并出来的结果如下:

0b0000000000000000000000000000001
0b0000000000000000000000000000100
---------------------------------
0b0000000000000000000000000000101

0b0000000000000000000000000000101 是我们的 lanes,接下来取负值

-lanes = 0b1111111111111111111111111111011

最后一步,再和本身的 lanes 做一个 & 操作:

0b0000000000000000000000000000101
0b1111111111111111111111111111011
---------------------------------
0b0000000000000000000000000000001

经过 & 操作之后,就把优先级最高的 lane 给分离出来了。

上下文

在 React 源码内部,有多个上下文:

// 未处于 React 上下文
export const NoContext = /*             */ 0b000;
// 处于 batchedUpdates 上下文
const BatchedContext = /*               */ 0b001;
// 处于 render 阶段
export const RenderContext = /*         */ 0b010;
// 处于 commit 阶段
export const CommitContext = /*         */ 0b100;

当执行流程到了 render 阶段,那么接下来就会切换上下文,切换到 RenderContext

let executionContext = NoContext; // 一开始初始化为没有上下文
executionContext |= RenderContext;

在执行方法的时候,就会有一个判断,判断当前处于哪一个上下文

// 是否处于 RenderContext 上下文中,结果为 true
(executionContext & RenderContext) !== NoContext// 是否处于 CommitContext 上下文中,结果为 false
(executionContext & CommitContext) !== NoContext

如果要离开某一个上下文

// 从当前上下文中移除 RenderContext 上下文
executionContext &= ~RenderContext;
// 是否处于 RenderContext 上下文中,结果为 false
(executionContext & CommitContext) !== NoContext

真题解答

题目:React 中哪些地方用到了位运算?

参考答案:

位运算可以很方便的表达“增、删、改、查”。在 React 内部,像 flags、状态、优先级等操作都大量使用到了位运算。

细分下来主要有如下的三个地方:

  • fiber 的 flags
  • lane 模型
  • 上下文

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/838698.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是Java可变长参数

从 Java 5 开始&#xff0c;Java 支持定义可变长参数&#xff08;Varargs&#xff09;&#xff0c;这使得我们可以在方法中传入不定长度的参数。这种功能极大地提高了编程的灵活性和代码的可读性。本文将详细解析可变长参数的用法、注意事项及实际应用。 基本用法 可变长参数…

java 中的运算符

Java 中的运算符分为以下几类&#xff0c;每类运算符都有特定的用途和规则。 1. 算术运算符 算术运算符用于执行基本的数学运算&#xff0c;包括加、减、乘、除和取模等。算术运算符可以用于基本数据类型&#xff08;如 int、double 等&#xff09;和它们的包装类&#xff08;如…

职业生涯第一课---“Redis分布式锁优化:确保唯一性与效率“

前言 最近因为刚入职公司开启自己的实习生涯&#xff0c;工作和毕设论文同步进行&#xff0c;导致有段时间没更新博客了&#xff0c;今天来分享一下最近学到的一些知识。 场景介绍 BOSS让我写一些接口&#xff0c;他提出这样一个需求&#xff0c;该接口的参数有多个&#xf…

C++并发:构建线程安全的队列

正文 线程安全队列的完整的类定义&#xff0c;其中采用了条件变量&#xff1a; #include <condition_variable> #include <memory> #include <mutex> #include <queue> template <typename T> class threadsafe_queue {private:mutable std::m…

谈谈 HTTP 的方法

目录 方法及其作用 扩展方法 GET 和 POST 的区别 PUT 和 POST 都是给服务器发送新增资源&#xff0c;有什么区别&#xff1f; PUT和PATCH都是给服务器发送修改资源&#xff0c;有什么区别&#xff1f; 方法及其作用 HTTP/0.9 只有1种请求方法&#xff1a;GETHTTP/1.0 新增…

【Linux】线程周边001之多线程

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.线程的理解 2.地址…

Github 2024-05-16 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-05-16统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目4TypeScript项目2C++项目1Go项目1HTML项目1CSS项目1Cuda项目1ChatGPT/Gemini UI: 跨平台聊天应用 创建周期:433 天开发语言:TypeSc…

吴恩达深度学习笔记:优化算法 (Optimization algorithms)2.8

目录 第二门课: 改善深层神经网络&#xff1a;超参数调试、正 则 化 以 及 优 化 (Improving Deep Neural Networks:Hyperparameter tuning, Regularization and Optimization)第二周&#xff1a;优化算法 (Optimization algorithms)2.8 Adam 优化算法(Adam optimization algor…

短视频批量剪辑,智能素材文案生成,多账号授权私信回复与矩阵发布素材功能合集系统,短视频矩阵助手源码搭建部署源码开源部署方案。

目录 一、短视频矩阵助手系统是什么&#xff1f; 二、短视频矩阵助手系统可以为企业解决什么问题&#xff1f; 短视频矩阵助手可以解决哪些问题&#xff1f; 三、短视频矩阵助手系统功能有哪些&#xff1f; 四、总结 一、短视频矩阵助手系统是什么&#xff1f; 短视频矩阵…

提升MySQL性能的秘密:了解表压缩功能的使用及其对性能的影响。

在MySQL数据库的使用中&#xff0c;对于字段类型设计大家可能都有一些思路和方式&#xff0c;但是针对存储方面的设计&#xff0c;在表结构设计之初可能就没考虑过&#xff0c;只有当业务发展到一定规模才意识到它所带来的问题严重性。而物理存储主要是考虑是否要启用表的压缩功…

如何把一张图片分割为网页布局

将一张图片分割为适合网页布局的步骤主要涉及使用图像编辑软件&#xff0c;如Adobe Photoshop&#xff0c;进行切片操作。以下是详细的步骤指导&#xff1a; 1. 准备图片 确保你有一张想要分割的图片&#xff0c;并且已经打开了Adobe Photoshop。 2. 选择切片工具 在工具栏…

环保科普馆如何互动化加深观众环保认知?

如今&#xff0c;多媒体技术的广泛应用&#xff0c;已经为环保、天文、生物等各类主题展厅注入了新的活力&#xff0c;在这些展馆中&#xff0c;它凭借独特的互动体验&#xff0c;以及深入浅出的教育方式&#xff0c;赢得了广大观众的热烈追捧。今天&#xff0c;我们就一同探讨…

阿里巴巴发布最新财报,营收重回增长轨道

KlipC报道&#xff1a;5月14日&#xff0c;阿里巴巴集团发布2024财年及第四财季最新财报&#xff0c;财报显示第四财季收入2218.74亿元&#xff0c;同比增长7%&#xff0c;超出市场预期。2024财年收入同比增长8%&#xff0c;达9411.68亿元。 第四财季净利润244.2亿元人民币&am…

【设计模式】JAVA Design Patterns——Aggregator Microservices(聚合器微服务模式)

&#x1f50d;目的 用户对聚合器服务进行一次调用&#xff0c;然后聚合器将调用每个相关的微服务。 &#x1f50d;解释 真实世界例子 网络市场需要有关产品及其当前库存的信息。 它调用聚合服务&#xff0c;聚合服务依次调用产品信息微服务和产品库存微服务&#xff0c;返回组合…

制作coco类型数据集

COCO格式数据集简介 COCO数据集是一个大型的、丰富的物体检测&#xff0c;分割和字幕数据集。这个数据集以scene understanding&#xff08;场景理解&#xff09;为目标&#xff0c;主要从复杂的日常场景中截取&#xff0c;图像中的目标通过精确的segmentation&#xff08;分…

道路运输驾驶员从业资格报考条件

根据《中华人民共和国道路运输条例》、交通运输部《道路运输从业人员管理规定》和上级交通运输部门的管理要求&#xff0c;参加道路运输从业资格培训时应遵守以下规定&#xff1a; 1、年龄不超过60周岁。 2、驾驶员要取得相应的机动车驾驶证&#xff08;C4以上&#xff09;。…

一步步教您轻松搭建YOLO训练环境(视频教程)

一步步教您轻松搭建YOLO训练环境 YOLO&#xff08;You Only Look Once&#xff09;是一种流行的实时目标检测算法。为了安装和部署YOLO的训练环境&#xff0c;你需要按照以下步骤进行操作&#xff1a; 一、前期准备 确定硬件要求&#xff1a;YOLO通常在具有GPU的计算机上运行…

不懂技术可以当项目经理吗?看完这篇你就知道了

项目经理作为项目的核心负责人&#xff0c;主要负责项目的规划、组织、协调和控制。 如果你不懂技术&#xff0c;但具备出色的项目管理技能&#xff0c;你仍然可以成功地管理项目。你可以通过与技术团队建立紧密的合作关系&#xff0c;明确项目需求&#xff0c;并依赖技术团队…

远程医疗系统

在远程医疗系统中&#xff0c;为了充分发挥其推动医疗科技创新的作用&#xff0c;系统可以包含以下功能点&#xff0c;并服务于不同类型的用户&#xff1a; 一、系统功能点 远程会诊系统&#xff1a; 实时视频会诊&#xff1a;医生与患者或医生与医生之间的实时视频交流。 病…

IntelliJ IDEA - 查看项目工程代码量统计

首先安装一个统计插件——Statistic 接着在左下角可以看到 Statistic Logo 插件&#xff0c;点击即可看到统计面板