Jun 01, 2021 Article blog
1. Why heuristic update algorithms appear
4. React16 heuristic update algorithm
Three days ago, the
React
team released the first
RC
version of
React17
the biggest feature of which was "No New Features."
So what has the
React
team been doing for more than a year, from
v17
v16
From
v15
to
v16
the
React
team spent two years refactoring
Stack Reconciler
in the source architecture into
Fiber Reconciler
and it must not have been that simple.
In fact, this version change does have a "new feature" -- replacing the heuristic update algorithm used internally.
It's just that this feature is not aware of the developer.
This article goes on to cover the following:
The operational performance of the framework is the key point that frame designers need to focus on when designing the framework.
Vue
uses template syntax to optimize the defined template at compile time.
React
pure
JS
writing is too flexible, leaving him innately deficient in compile-time optimization.
Therefore,
React
optimization is primarily at runtime.
React
has been working runtime optimization.
For example,
React15
batchedUpdates
(bulk updates).
That is, multiple
setState
in the context of the same event callback function trigger only one update.
However, if a single update is time-consuming, the page will still get stuck (which is common in a large application with a long maintenance time).
This is because
React15
update process is synchronized and cannot be interrupted once the update is started until the page is rendered.
To address the problem of page carding caused by long-term thread consumption of synchronous updates, and to explore more possibilities for runtime optimization,
React
began refactoring and continues to do so today.
The goal of the refactoring is to implement
Concurrent Mode
(Recommended tutorial: React tutorial)
The purpose of
Concurrent Mode
is to implement an interruptable/recoverable update mechanism.
It consists of two parts:
Among them, the co-architecture is
Fiber Reconciler
implemented in
React16
We can interpret
Fiber Reconciler
as
React
own
Generator
A detailed description of Fiber Reconciler from concept to source code can be found here
The co-architecture allows updates to be interrupted when needed, giving the browser time to complete style layout and style drawing, reducing the appearance of catons (dropped frames).
As the browser enters the next event loop, the co-architecture can resume the interrupt or discard the previous update and restart the new update process.
Heuristic update algorithm is the algorithm that controls how the co-program architecture works.
What does heuristics for heuristic update algorithms mean?
Heuristics refer to updates that are not scheduled by explicit assignment, but by priority.
The priority comes from the research results of human-computer interaction.
Like what:
The results of human-computer interaction show that:
Based on this, in React16
更新
priority triggered by the input to the input box > the update priority is triggered when the request data is
更新
Algorithmic implementation In
React16、17
this.setState
within a component produces a list data structure update within the
fiber
node
update
the component.
Where
update.expirationTimes
is a timestamp-like field that represents priority.
expirationTimes
is literally understood as the expiration time.
The closer the value is to the current time, the higher the
update
priority.
When
update.expirationTimes
the current time, it means that the
update
expires and the priority becomes the highest (i.e. synchronization).
Multiple
fiber
nodes in a
fiber
tree may have multiple
update
Each time
Fiber Reconciler
schedules an update, one of all
update.expirationTimes
for all
fiber
expirationTimes
is selected (generally the largest choice) as the priority for this update.
and
fiber
build the new
fiber
tree down from the root fiber node.
If a
fiber
node contains
update
during the build process, and
update.expirationTimes >= expirationTimes
The change in
state
corresponding to the
update
is reflected in this update.
It can be understood that one priority is selected for each update, and the final page renders a snapshot of the
update
corresponding to that priority.
For example, we have the
fiber
tree shown in the figure, which has not yet been updated, so there is no
fiber
tree under construction.
When a low-priority
update
is created in C, the update is scheduled, and the priority selected for this update is low priority.
Start building a new
fiber
tree (right).
At this point, we create a high priority
update
D.
This interrupts the ongoing low-priority update and restarts the generation of a
fiber
tree with a high priority.
There are no rendering operations because previous updates have been interrupted, and there is no change in the view (left).
This update selects a high priority and C's
update
is skipped.
When the update is complete, the new
fiber
tree is rendered into view.
Because C is skipped, it is not reflected in the view (left).
Next we trigger a high priority
update
E.
C although it contains a low-priority
update
over time his
expirationTimes
has expired and becomes a high-priority.
So this update will have changes to both C E
fiber
nodes.
When the update is finally complete, the view is as follows:
Models that measure the size
expirationTimes
work well if only CPU operations such as interrupting/continuing are considered.
However,
expirationTimes
model does not meet the IO operation (Delay).
Under this model, high-priority IO tasks (Quests) interrupt low-priority CPU tasks.
Remember, every update is a priority update standard for an entire tree, not just a component, even if the source of the update is actually a component.
expirationTimes
model can only distinguish between > and the case of
>=expirationTimes
To extend
Concurrent Mode
capability boundary, a more granular heuristic priority update algorithm is required.
(Recommended tutorial: React Getting Started Instance Tutorial)
The ideal model is that you can specify any number of priorities at which updates generate a snapshot of the page for
update
However, under the existing architecture, there are bottlenecks in the implementation of this scheme.
Under compromise,
React17
solution is to specify a continuous priority interval, and each update generates a snapshot of the corresponding page at the priority included in the interval.
This priority interval model is called
lanes
(lane models).
This is done by using a 31-bit binary to represent 31 possibilities.
bit
is referred to as a
lane
(lane) that represents priority
lane
lanes is called a lanes and
lanes
a set of priorities
As you can see from the source code, from the Blue Line all the way down, each bit corresponds to a
lane
or
lanes
When
update
is generated, one of the following priorities is obtained based on
React16
same heuristic approach:
export const SyncLanePriority: LanePriority = 17; e xport const SyncBatchedLanePriority: LanePriority = 16; e xport const InputDiscreteLanePriority: LanePriority = 14; e xport const InputContinuousLanePriority: LanePriority = 12; e xport const DefaultLanePriority: LanePriority = 10; e xport const TransitionShortLanePriority: LanePriority = 8; export const TransitionLongLanePriority: LanePriority = 6;
The higher the value, the higher the priority.
Like what:
update
generated by triggering
this.setState
in an event callback results in
InputDiscreteLanePriority
update
get
SyncLanePriority
Next,
update
looks for unoccupied
lane
with
priority
as a clue.
If the current
fiber
tree already exists and the updated lanes contain the
lane
update
lanes
to look for additional
lane
For example,
InputDiscreteLanePriority
lanes
to
InputDiscreteLanes
The 4th and 5th digits are 1 const InputDiscrete Lanes: Lanes s 0b000000000000000000000000000000110000;
The
lanes
contain the 4th, 5th, 2
bit
bits.
If it is
The fifth position is 1 0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
The fifth lane
lane
already occupied, and the
update
can attempt to occupy the latter, that is
The fourth position is 1 0b0000000000000000000000000000000000000000000000000000000000000000
If both
lane
of
InputDiscreteLanes
are occupied, the
update
of the update drops to
InputContinuousLanePriority
and continues to look for spare
lane
The process is like this: there is an open-air car park (lanes) on each floor of the mall (with different priorities) and multiple parking spaces in the car park.
Let's drive to the top floor to find a parking space (lane) and if there is no parking space we will continue to look for it on the next floor.
until a spare parking space is found.
Because
lanes
can contain multiple
lane
it is convenient to distinguish between IO operations (DNAs) and CPU operations.
When the build
fiber
tree enters the build
Suspense
subtree, the
lane
of the is inserted into the
Suspense
selected for this update.
lanes
When the build leaves the
Suspense
subtree,
Suspense lane
is removed from the
lanes
of this update.
(Recommended micro-class: React micro-course)
React16
expirationTimes
model can only distinguish between
>=expirationTimes
updated >.
React17
lanes
model can select an update interval and dynamically add or subtract priorities to the interval to handle more granular updates.
Here's a look at the new feature of
React17
the heuristic update algorithm, which I hope will help you.