九、React中的位运算

位运算的基础知识

所谓二进制,就是以二为底的一种计数方式。逢二进一

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

比如我们后台管理系统,一般会针对权限的控制,一般这个使用的就是二进制

0b10000000
0b01000000
0b00100000
0b00010000

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

比如我门有以下权限A、B、C,我们要根据不同的权限做不同的事情:

// 权限 A B C 
if (value === "A") {

} else if (value === "B") {

} else if (value === "C") {
    
}
// 如果遇到既有A权限又有B权限 那么就要重新再定义个一个值
// 如果有很多 我们就要定义很多的值来处理
if(value === "AB"){
 .....
}

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

在这种情况下,我们使用二进制会方便很多 

二进制相关的运算

  • 与 (&):只要有一位为0,最终就为0
  • 或( | ):只要有一位为1,最终就为1
  • 非(~):就是0 1 互换
  • 异或(^):如果两个二进制位不相同,那么结果为1,相同为0

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

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

其中 0就算代表没有权限,1代表有权限

0000 0001 表示有创建的权限

0000 0011 表示编辑和创建的权限

添加权限 

直接使用或运算即可

0000 0011 表示编辑和创建的权限,再加一个打印的权限

0000 0011 | 0100 0011 = 0100 0011

删除权限

直接使用异或就可以

0100 0011 表示打印、编辑和创建的权限,我们要删除打印的权限

0100 0011 ^ 0100 0000 = 0000 0011

判断是不是有某一个权限

可以用与操作符来判断

0100 0011 表示打印、编辑和创建的权限,我们来判断是不是有打印的权限,有没有下载权限

0100 0000 & 0100 0000 = 0100 0000

判断是否有 打印的 权限,做 与 操作,得到了 打印权限的本身,说明就有这个权限

0100 0011 & 1000 0000 = 0000 0000 

判断是否有 下载的 权限,做 与 操作,得到了 全为 0 ,说明就没有这个权限

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;
// ...

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

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

export const NoFlags = /*                      */ 0b000000000000000000000000000;
export const PerformedWork = /*                */ 0b000000000000000000000000001;
export const Placement = /*                    */ 0b000000000000000000000000010;
export const DidCapture = /*                   */ 0b000000000000000000010000000;
export const Hydrating = /*                    */ 0b000000000000001000000000000;
let flag = NoFlags;
// 合并多个 标记
flag = flag | PerformedWork | Placement;
if (flag & PerformedWork) {
  console.log("PerformedWork");
}
if (flag & Placement) {
  console.log("Placement");
}

lane 模型

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

const NoLanes=                         / 0b0000000000000000000000000000000;
const NoLane=                          / 0b0000000000000000000000000000000;

const SyncLane=                         / 0b0000000000000000000000000000001;
const SyncBatchedLane=                  / 0b0000000000000000000000000000010;

const InputDiscreteHydrationLane=       / 0b0000000000000000000000000000100;
const InputDiscreteLanes=                     / 0b0000000000000000000000000011000;

const InputContinuousHydrationLane=            / 0b0000000000000000000000000100000;
const InputContinuousLanes=                  / 0b0000000000000000000000011000000;

/**
 * 
 * @param {*} lanes 一套lane的组合
 * @returns 
 */
function getHighestPriorityLanes(lanes){
    // 从lanes的组合中,分离出优先级最高的 lane
    switch (getHighestPriorityLane(lanes)){
        case SyncLane:
            return ''
    }
}

 lane 在表示优先级的时候,大致是这样的:

比如说我们有三个lane

0000 0001

0000 0010

0010 0000

那么lanes 就表示 一套lane的组合,组合到一起就表示 lanes 0010 0011

getHighestPriorityLane 这个方法就是表示要分离出优先级最高的

getHighestPriorityLane(0010 0011) ==>  0000 0001

function getHighestPriorityLane(lanes){
    return lanes & -lanes
}

 补码: 反码 + 1

const SyncLane = 0b0000000000000000000000000000001;
const InputContinuousLanes = 0b0000000000000000000000000000100;

lanes: SyncLane | InputContinuousLanes = 0b0000000000000000000000000000101;
-lanes: 0b1111111111111111111111111111011

lanes && -lanes = 0b0000000000000000000000000000001

上下文

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

const NoContext = 0b000; // 位处于React上下文
const BatchedContext = 0b001; // 位处于Batched上下文
const RenderContext = 0b010; // 位处于Render上下文
const CommitContext = 0b100; // 位处于Commit上下文

// 上下文切换
let executionContext = NoContext;
executionContext |= RenderContext;

// 判断当前处于哪个上下文
(executionContext & RenderContext) !== NoContext;
(executionContext & CommitContext) !== NoContext;

// 判断是否移除某个上下文
executionContext &= ~RenderContext;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值