本文对应的 react
版本是 18.2.0
在阅读源码时,react
有很多位操作,这些位操作大都是对 lane
的操作
如果不了解这些位操作含义,看源码时会一脸懵逼:
- 为什么运算前的值和运算后的值一样?
- 运算后这个值有什么用
react
是怎么怎么判断优先级的高低
什么是 lane
lane
是 react@17
中用于表示任务的优先级,是对 expirationTime
的重构
lane
是一个 32
位的二进制数,每个二进制位表示 1
种优先级,优先级最高的 SyncLane
为 1
,其次为 2
、4
、8
等
lanes
是一个整数,该整数所有为二进制位为 1
对应的优先级任务都将被执行
注意:
lane
的长度是31
位,react
这么做是为了避免符号位参与运算
react
对 lane
的操作有 8
种:
lane & lane
lane & lanes
lanes & ~lane
lanes1 & lanes2
lane | lane
lanes2 |= lanes1 & lane
lane *= 2
和lane <<= 1
lanes & -lanes
在下面将会举例详细介绍这些操作,这里先介绍一下 lane
的值:
lanes
值为 0b0000000011111111111111110000000
,表示有多个任务的优先级。
TransitionLane1
值为 0b0000000000000000000000010000000
,表示单个任务的优先级
TransitionLane2
值为 0b0000000000000000000000100000000
,表示单个任务的优先级
1. lane & lane
用来判断是不是同一个 lane
,两个 lane
是否有相同的位为 1
(取交集)
比如:lane & TransitionLane1
,如果 lane
的值为 0b0000000000000000000000010000000
,则输出 0b0000000000000000000000010000000
,否则输出 0
用于 getLabelForLane 函数
2. lane & lanes
用来判断 lanes
中是否有 lane
,是否有相同的位为 1
(取交集)
如果想判断 lanes
中是否有 lane
,进行如下计算:
将 TransitionLane1
和 lanes
进行按位与,得到 lane & lanes
,它的值是 0b0000000000000000000000010000000
,和 TransitionLane1
值相同,说明 lanes
中有 TransitionLane1
任务
用于 isTransitionLane 等函数
3. lanes & ~lane
用来从 lanes
中删除 lane
(取差集)
如果想去从 lanes
中删掉 lane
,具体步骤如下:
- 对
TransitionLane1
取反,得到~lane
,即0b1111111111111111111111101111111
- 对
lanes
和~lane
进行按位与运算,得到lanes & ~lane
,即0b0000000011111111111111100000000
- 这样就把
lanes
中的TransitionLane1
置为了0
,也就是去掉了这个任务
用于 getNextLanes 等函数
4. lanes1 & lanes2
用于判断 lanes1
中是否有 lane
属于 lanes2
(取交集)
如果想判断 lanes1
中是否有 lane
属于 lanes2
,进行如下计算:
- 假设
lanes2
为SyncDefaultLanes
,它是由InputContinuousHydrationLane | InputContinuousLane |DefaultHydrationLane | DefaultLane
组成的,即0b0000000000000000000000000111100
- 当
lanes1
的3 ~ 6
位为1
,即lanes1
为0b0000000000000000000000000111100
- 则
lanes1 & lanes2
的值为lanes1
,即0b0000000000000000000000000111100
- 说明
lanes1
中有lanes2
中的lane
这种用法有种变形:lanes & (lane | lane)
用于 includesNonIdleWork、includesSyncLane 等函数
5. lane | lane
用于将多个 lane
合并为一个 lanes
(取并集)
合并两个 lane
,TransitionLane1 | TransitionLane2
,得到的值为 0b0000000000000000000000110000000
用于 markHiddenUpdate 等函数
6. lanes2 |= lanes1 & lane
用于将 lanes1
中的 lane
合并到 lanes2
中(先取交集,再取并集)
这种写法等于:lanes2 = lanes2 | (lanes1 & lane)
如果想从 lanes1
中取出 lane
,并将它合并到 lanes2
中,进行如下计算:
lanes1
为InputContinuousHydrationLane | InputContinuousLane
,即0b0000000000000000000000000001100
lanes2
为DefaultHydrationLane | DefaultLane
,即0b0000000000000000000000000110000
lane
为InputContinuousLane
,即0b0000000000000000000000000001000
lanes1 & lane
的值为InputContinuousLane
,即0b0000000000000000000000000001000
lanes2 |= lanes1 & lane
的值为DefaultHydrationLane | DefaultLane | InputContinuousLane
,即0b0000000000000000000000000111100
lanes2
中多了InputContinuousLane
这个任务
用于 markRootMutableRead、markRootPinged 等函数
7. lane *= 2 和 lane <<= 1
都是将 lane
左移一位,一般来说位运算比乘法运算快
TransitionLane1 *= 2
和 TransitionLane1 <<= 1
的结果都是 0b0000000000000000000000100000000
用于 getLaneLabelMap、claimNextRetryLane 等函数
8. lanes & -lanes
从 lanes
中找出最高优先级的 lane
如果想找出 lanes
中最高优先级的 lane
,进行如下计算:
- 对
lanes
取反,得到~lanes
,即0b1111111100000000000000001111111
- 末尾加
1
,得到-lanes
,即0b1111111100000000000000010000000
- 对
lanes
和-lanes
进行按位与运算,得到lanes & -lanes
,即0b0000000000000000000000010000000
- 这样就找出了
lanes
中最高优先级的lane
用于 getHighestPriorityLane 函数
补充说明:
下面二进制数都是 32
位带符号位二进制数
~ 是按位取反
十进制数 4
,按位取反是 -5
,记做 ~4
,计算逻辑如下:
- 将十进制数
4
转换为二进制数为0b00000000000000000000000000000100
- 按位取反,即将
1
变为0
,将0
变为1
,得到0b11111111111111111111111111111011
。 - 符号位不变,其他位取反,得到
0b10000000000000000000000000000100
- 末位加
1
,得到0b10000000000000000000000000000101
- 将二进制数转换为十进制数,得到
-5
。
js 中按取反
js
中按位取反只是一个按位取反,并不表示按位取反后的数是实际的负数
- 十进制整数
4
,转换为二进制数为0b00000000000000000000000000000100
- 按位取反,即将
1
变为0
,将0
变为1
,得到0b11111111111111111111111111111011
4 & ~4
结果是 0
因为 4
的二进制数为 0b00000000000000000000000000000100
,~4
的二进制数为 0b11111111111111111111111111111011
,不是 0b10000000000000000000000000000101
也就是说 ~4
的二进制数是 4
的二进制数取反
js 中的负数
十进制整数 14
,负数为 -14
14 & -14
结果是 2
为什么结果会是 2
呢?
因为 14
的二进制数为 0b00000000000000000000000000001110
,-14
的二进制数为 0b11111111111111111111111111110010
,不是 0b10000000000000000000000000001110
也就是说,-14
的二进制数是 14
的二进制数取反后再加 1
最后
- 在
js
中对于二进制数操作要特别小心:~
是按位取反(末尾不加一),-
取反末尾加一 -lane === (~lane + 1)
总结
lane & lane
:用来判断是不是同一个lane
(是否有相同的位为1
,取交集)lane & lanes
:用来判断lanes
中是否有lane
(是否有相同的位为1
,取交集)lanes & ~lane
:用来从lanes
中删除lane
(取差集)lanes1 & lanes2
:用于判断lanes1
中是否有lane
属于lanes2
(取交集)lane | lane
:用于将多个lane
合并为一个lanes
(取并集)lanes2 |= lanes1 & lane
:用于将lanes1
中的lane
合并到lanes2
中(先取交集,再取并集)lane *= 2
和lane <<= 1
:都是将lane
左移一位lanes & -lanes
:从lanes
中找出最高优先级的lane
往期文章
更多 react
源码文章