9
头图

Hi everyone, I'm Kasong.

In the past two years, many friends and I have React source code of 06163c4e061d66, such as:

  • Why does the scheduler use a small top heap data structure instead of using an array directly?
  • Can we use arrays directly in various singly linked lists and circular linked lists in the source code?
  • Are various bit operations in the source code necessary?

As a business-dependent framework, in order to improve a little runtime performance, React never hesitated to write the source code very complicated.

A large number of bit operations are used where states, flag bits, and priority operations are involved.

This article will explain the more representative parts. After learning, show your hand when encountering similar scenes, you are the most beautiful boy in the business line.

Several common bit operations

In JS , the -bit operation will first be converted to Int32 (32-bit signed integer), after executing -bit operation, Int32 corresponds to a floating-point number.

In React , three kinds of bitwise operators are mainly used-bitwise AND, bitwise OR, and bitwise NOT.

Bitwise and (&)

For each of the two binary operands bit , if both are 1, the result is 1, otherwise it is 0.

For example, to calculate 3 & 2 , first convert the operand to Int32 :

// 3对应的 Int32
0b000 0000 0000 0000 0000 0000 0000 0011 
// 2对应的 Int32
0b000 0000 0000 0000 0000 0000 0000 0010 

For the sake of intuition, we exclude the first 0 and only keep the last 8 bits (the actual calculation should be 32 bits):

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

Therefore, the 3 & 2 is converted into a floating-point number to 2.

Bitwise or (|)

For each of the two binary operands bit , if both are 0, the result is 0, otherwise it is 1.

Calculation 10 | 3 :

  0000 1010
| 0000 0011
-----------
  0000 1011

The result of the calculation is converted to a floating point number as 11.

Bitwise not (~)

bit of a binary operand, perform the inversion operation bit by bit (0, 1 interchange)

For ~3 , convert 3 to Int32 then reverse it bit by bit:

// 3对应的 Int32
0b000 0000 0000 0000 0000 0000 0000 0011 
// 逐位取反
0b111 1111 1111 1111 1111 1111 1111 1100

The result of the calculation is -4 after being converted into a floating point number.

If you have doubts about this result, you can learn about complement

Let us look at the application of React

Mark status

React source code, and it is often necessary to determine which context is currently in when executing a function.

Suppose there are three contexts:

// A上下文
const A = 1;
// B上下文
const B = 2;
// 没有处在上下文
const NoContext = 0;

When entering a certain context, you can use bitwise OR operation flag to enter:

// 当前所处上下文
let curContext = 0;

// 进入A上下文
curContext |= A;

We use 8-bit binary as an example (again, it should be Int32 actually, here is for simplification), curContext and A perform the OR operation of 16163c4e062196:

  0000 0000  // curContext
| 0000 0001  // A
-----------
  0000 0001

At this time, you can combine the AND operation of NoContext and 06163c4e0621be to determine whether it is in a certain context:

// 是否处在A上下文中 true
(curContext & A) !== NoContext

// 是否处在B上下文中 false
(curContext & B) !== NoContext

After leaving a certain context, combine the bitwise AND and bitwise non-removal flags:

// 从当前上下文中移除上下文A
curContext &= ~A;

// 是否处在A上下文中 false
(curContext & A) !== NoContext

curContext and ~A perform the AND operation of 16163c4e06224d:

  0000 0001  // curContext
& 1111 1110  // ~A
-----------
  0000 0000

That is, curContext is removed from A .

When multiple states need to be processed at the same time in a business, you can use upper-level computing techniques.

Priority calculation

In React this.setState under different circumstances will have different priorities. The comparison and selection between priorities also use bit operations.

Specifically, in React 31 bit bits are used to save update (the reason why it is 31 instead of 32 is because Int32 is the sign bit, and no specific number is stored).

The lower the bit bit, the higher the update priority (the more it needs priority processing).

For example, suppose there are 2 updates in the current application:

0b000 0000 0000 0000 0000 0000 0001 0001

Among them, the first update priority is the highest (need to be synchronized), and the fifth is the default priority.

React often necessary to find out which bit the current highest priority update is (the first one in the above example), the method is as follows:

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

Explain, because Int32 is complement , so -lanes can be regarded as the following two-step operation:

  1. Lanes negated (~lanes)
  2. plus 1

For intuitiveness, it is represented by 8 bits:

lanes  0001 0001
~lanes 1110 1110 // 第一步
+1     1110 1111 // 第二步

Then lanes & -lanes as follows:

  0001 0001 // lanes  
& 1110 1111 // -lanes
-----------
  0000 0001

The first one is obtained (the highest priority among existing updates).

Summarize

Although bit operations are not often used in business, it is a convenient and efficient way to perform bit operations in specific scenarios.

Do you love this wave of operations?

Welcome to join the human high-quality front-end framework research group , take flight


卡颂
3.1k 声望16.7k 粉丝