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.hqwc.cn/news/706722.html

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

相关文章

青少年CTF练习平台Crypto题解

四重加密 下载附件后&#xff0c;得到一个rar文件&#xff0c;发现被加密&#xff0c;无法解压 使用Bandizip打开 注释中有段编码OFZW4Y3UMY CyberChef base64解码得到第一层压缩包密码 qsnctf 打开后有一个文本文档 内容如下 NCR&#xff0c;HTML解码 得到一串密…

Linux下mysql备份

参考文章&#xff1a; Linux实现MySQL数据库数据自动备份&#xff0c;并定期删除以前备份文件-CSDN博客文章浏览阅读7.2k次&#xff0c;点赞7次&#xff0c;收藏29次。引言在学习过程中遇到了一个问题&#xff0c;见图&#xff1a;当我进入服务器的数据库时&#xff0c;原来的…

国内用户如何免费抢先体验GPT-4o(国内如何免费使用各类GPT产品,包含chatgpt、claude、Gemini等)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 GPT-4o抢先体验 📒📝 方法介绍🎈 永久免费🎈 其他工具⚓️ 相关链接 ⚓️📖 介绍 📖 “OpenAI的最新突破——GPT-4o已经到来,国内用户如何免费体验这一AI革命性产品?” 随着OpenAI的GPT-4o模型的发布,全球AI领域…

JavaScript对象设计哲学:八种模式塑造高效代码

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言 &#x1f680;二、Object 构造函数 &#x1f9f1;&#x1f4cc; 基本用法&#x1f4cc; 重要性&#x1f4cc; 实际应用案例 三、对象字面量 &#x1f4d8;&#x1f4cc; 定义属性&#x1f4cc; 定义方法&#x1f4…

Linux ps命令详细参数

一、简介 在Linux系统中&#xff0c;ps(Process Status的缩写)命令常常用来用来列出系统中当前运行的进程。ps命令列出的是当前那些进程的快照&#xff0c;就是执行ps命令的那个时刻的那些进程&#xff0c;如果想要动态的显示进程信息&#xff0c;就可以使用top命令。要对进程…

亚马逊Prime Day旺季备货遭遇美国海关查验高峰,应对策略全攻略!

随着全球化贸易的日益繁荣&#xff0c;跨境电商企业在旺季备货时面临着巨大的挑战&#xff0c;尤其是当遇到美国海关查验潮时&#xff0c;如何应对成为众多商家关注的焦点。本文将从分析美国海关查验的原因入手&#xff0c;为商家提供一系列应对策略和建议。 一、美国海关查验潮…

Python | Leetcode Python题解之第86题分隔链表

题目&#xff1a; 题解&#xff1a; class Solution:def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:sml_dummy, big_dummy ListNode(0), ListNode(0)sml, big sml_dummy, big_dummywhile head:if head.val < x:sml.next headsml sm…

echers配置项:数据过多时,折叠数据缩放查看

当数据过多时&#xff0c;如上图所示的时间点&#xff0c;会自动折叠&#xff0c;此时鼠标缩放还不起作用&#xff0c;我们配置如下代码 let option {dataZoom: [{startValue: 05:00}, // 这个值需要跟 第一条 时间数据对应上{type: inside}], }配置后&#xff0c;就可以进行…

NodeJS V8引擎内存和垃圾回收器

关于max_old_space_size max_old_space_size参数用于指定V8引擎的老生代内存的最大大小。通过增加max_old_space_size参数的值&#xff0c;我们可以提供更多的内存给V8引擎&#xff0c;从而提高应用程序的性能和稳定性。 既然提到了老生代&#xff0c;就不得不提下什么是垃圾&…

项目管理重点及笔记【太原理工大学24年】

为了自己复习写的&#xff0c;可能会有不清楚&#xff0c;可以选择性看可以讨论&#xff0c;但别骂我写的什么烂东西&#xff0c;&#xff0c;&#xff0c;&#xff08;电脑看排版更好看些&#xff09; 目录 一、IT项目管理概述 二、IT项目组织环境与管理过程 三、整体管理 四、…

5W 3KVAC隔离 宽电压输入 AC/DC 电源模块——TP05AL系列

TP05AL系列产品是一款经济型开板式开关电源&#xff0c;输出功率为5W&#xff0c;具有可靠性高、小体积、性价比高等特点&#xff0c;广泛用于工控和电力仪器、仪表、智能家居等相关行业。

LeetCode-1953. 你可以工作的最大周数【贪心 数组】

LeetCode-1953. 你可以工作的最大周数【贪心 数组】 题目描述&#xff1a;解题思路一&#xff1a;贪心&#xff0c;关键点是找到(工作最长时间的工作longest )与(剩余其他工作加起来的时间总和rest )的关系。解题思路二&#xff1a;证明解题思路三&#xff1a;简化 题目描述&am…