Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track entangled lanes separately from update lane #27505

Merged
merged 2 commits into from
Oct 15, 2023

Conversation

acdlite
Copy link
Collaborator

@acdlite acdlite commented Oct 12, 2023

A small refactor to how the lane entanglement mechanism works. We can now distinguish between the lane that "spawned" a render task (i.e. a new update) versus the lanes that it's entangled with. Both the update lane and the entangled lanes will be included while rendering, but by keeping them separate, we don't lose the original priority.

In practical terms, this means we can now entangle a low priority update with a higher priority lane while rendering at the lower priority.

To do this, lanes that are entangled at the root are now tracked using the same variable that we use to track the "base lanes" when revealing a previously hidden tree — conceptually, they are the same thing. I also renamed this variable (from subtreeLanes to entangledRenderLanes) to better reflect how it's used.

My primary motivation is related to useDeferredValue, which I'll address in a later PR.

I updated one of the tests related to synchronous popstate transitions
to clarify what the desired behavior is. It's really about what happens
if a popstate transition suspends. It should not cause an error, and
the transition should be allowed to finish once the promise resolves.

Ideally, if the transition suspends, it should completely revert back
to the default behavior for transitions — i.e. it should no longer be
treated as synchronous. Currently we don't do that, and when the promise
resolve the transition will still be rendered synchronously, but we can
improve this later.
@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Oct 12, 2023
@react-sizebot
Copy link

react-sizebot commented Oct 12, 2023

Comparing: e61a60f...717595f

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.min.js +0.09% 174.53 kB 174.68 kB +0.04% 54.29 kB 54.32 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.09% 176.61 kB 176.77 kB +0.09% 54.94 kB 54.99 kB
facebook-www/ReactDOM-prod.classic.js +0.08% 565.12 kB 565.55 kB +0.11% 99.42 kB 99.53 kB
facebook-www/ReactDOM-prod.modern.js +0.08% 548.98 kB 549.40 kB +0.11% 96.50 kB 96.60 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable-semver/react-reconciler/cjs/react-reconciler.development.js +0.22% 931.93 kB 933.98 kB +0.22% 200.11 kB 200.55 kB
oss-stable/react-reconciler/cjs/react-reconciler.development.js +0.22% 931.95 kB 934.01 kB +0.22% 200.14 kB 200.58 kB
oss-experimental/react-reconciler/cjs/react-reconciler.development.js +0.22% 942.04 kB 944.09 kB +0.22% 202.00 kB 202.46 kB
oss-stable-semver/react-test-renderer/cjs/react-test-renderer.development.js +0.20% 813.99 kB 815.64 kB +0.25% 178.18 kB 178.62 kB
oss-stable/react-test-renderer/cjs/react-test-renderer.development.js +0.20% 814.02 kB 815.67 kB +0.25% 178.21 kB 178.66 kB
oss-experimental/react-test-renderer/cjs/react-test-renderer.development.js +0.20% 815.38 kB 817.03 kB +0.25% 178.45 kB 178.89 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-dev.js +0.20% 826.50 kB 828.16 kB +0.23% 179.67 kB 180.09 kB

Generated by 🚫 dangerJS against 717595f

A small refactor to how the lane entanglement mechanism works. We can
now distinguish between the lane that "spawned" a render task (i.e. a
new update) versus the lanes that it's entangled with. Both the update
lane and the entangled lanes will be included while rendering, but
by keeping them separate, we don't lose the original priority.

In practical terms, this means we can now entangle a low priority update
with a higher priority lane while rendering at the lower priority.

To do this, lanes that are entangled at the root are now tracked using
the same variable that we use to track the "base lanes" when revealing
a previously hidden tree — conceptually, they are the same thing. I
also renamed this variable (from subtreeLanes to entangledRenderLanes)
to better reflect how it's used.

My primary motivation is related to useDeferredValue, which I'll address
in a later PR.
@acdlite acdlite merged commit 309c8ad into facebook:main Oct 15, 2023
36 checks passed
github-actions bot pushed a commit that referenced this pull request Oct 15, 2023
A small refactor to how the lane entanglement mechanism works. We can
now distinguish between the lane that "spawned" a render task (i.e. a
new update) versus the lanes that it's entangled with. Both the update
lane and the entangled lanes will be included while rendering, but by
keeping them separate, we don't lose the original priority.

In practical terms, this means we can now entangle a low priority update
with a higher priority lane while rendering at the lower priority.

To do this, lanes that are entangled at the root are now tracked using
the same variable that we use to track the "base lanes" when revealing a
previously hidden tree — conceptually, they are the same thing. I also
renamed this variable (from subtreeLanes to entangledRenderLanes) to
better reflect how it's used.

My primary motivation is related to useDeferredValue, which I'll address
in a later PR.

DiffTrain build for [309c8ad](309c8ad)
acdlite added a commit that referenced this pull request Oct 17, 2023
### Based on #27505

If a parent render spawns a deferred task with useDeferredValue, but the
parent render suspends, we should not wait for the parent render to
complete before attempting to render the final value.

The reason is that the initialValue argument to useDeferredValue is
meant to represent an immediate preview of the final UI. If we can't
render it "immediately", we might as well skip it and go straight to the
"real" value.

This is an improvement over how a userspace implementation of
useDeferredValue would work, because a userspace implementation would
have to wait for the parent task to commit (useEffect) before spawning
the deferred task, creating a waterfall.
github-actions bot pushed a commit that referenced this pull request Oct 17, 2023
### Based on #27505

If a parent render spawns a deferred task with useDeferredValue, but the
parent render suspends, we should not wait for the parent render to
complete before attempting to render the final value.

The reason is that the initialValue argument to useDeferredValue is
meant to represent an immediate preview of the final UI. If we can't
render it "immediately", we might as well skip it and go straight to the
"real" value.

This is an improvement over how a userspace implementation of
useDeferredValue would work, because a userspace implementation would
have to wait for the parent task to commit (useEffect) before spawning
the deferred task, creating a waterfall.

DiffTrain build for [b2a68a6](b2a68a6)
kodiakhq bot pushed a commit to vercel/next.js that referenced this pull request Oct 18, 2023
jerrydev0927 added a commit to jerrydev0927/react that referenced this pull request Jan 5, 2024
### Based on facebook/react#27505

If a parent render spawns a deferred task with useDeferredValue, but the
parent render suspends, we should not wait for the parent render to
complete before attempting to render the final value.

The reason is that the initialValue argument to useDeferredValue is
meant to represent an immediate preview of the final UI. If we can't
render it "immediately", we might as well skip it and go straight to the
"real" value.

This is an improvement over how a userspace implementation of
useDeferredValue would work, because a userspace implementation would
have to wait for the parent task to commit (useEffect) before spawning
the deferred task, creating a waterfall.

DiffTrain build for [b2a68a65c84b63ac86930d88ae5c84380cbbdeb6](facebook/react@b2a68a6)
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
A small refactor to how the lane entanglement mechanism works. We can
now distinguish between the lane that "spawned" a render task (i.e. a
new update) versus the lanes that it's entangled with. Both the update
lane and the entangled lanes will be included while rendering, but by
keeping them separate, we don't lose the original priority.

In practical terms, this means we can now entangle a low priority update
with a higher priority lane while rendering at the lower priority.

To do this, lanes that are entangled at the root are now tracked using
the same variable that we use to track the "base lanes" when revealing a
previously hidden tree — conceptually, they are the same thing. I also
renamed this variable (from subtreeLanes to entangledRenderLanes) to
better reflect how it's used.

My primary motivation is related to useDeferredValue, which I'll address
in a later PR.
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
)

### Based on facebook#27505

If a parent render spawns a deferred task with useDeferredValue, but the
parent render suspends, we should not wait for the parent render to
complete before attempting to render the final value.

The reason is that the initialValue argument to useDeferredValue is
meant to represent an immediate preview of the final UI. If we can't
render it "immediately", we might as well skip it and go straight to the
"real" value.

This is an improvement over how a userspace implementation of
useDeferredValue would work, because a userspace implementation would
have to wait for the parent task to commit (useEffect) before spawning
the deferred task, creating a waterfall.
bigfootjon pushed a commit that referenced this pull request Apr 18, 2024
A small refactor to how the lane entanglement mechanism works. We can
now distinguish between the lane that "spawned" a render task (i.e. a
new update) versus the lanes that it's entangled with. Both the update
lane and the entangled lanes will be included while rendering, but by
keeping them separate, we don't lose the original priority.

In practical terms, this means we can now entangle a low priority update
with a higher priority lane while rendering at the lower priority.

To do this, lanes that are entangled at the root are now tracked using
the same variable that we use to track the "base lanes" when revealing a
previously hidden tree — conceptually, they are the same thing. I also
renamed this variable (from subtreeLanes to entangledRenderLanes) to
better reflect how it's used.

My primary motivation is related to useDeferredValue, which I'll address
in a later PR.

DiffTrain build for commit 309c8ad.
acdlite added a commit to acdlite/react that referenced this pull request Aug 20, 2024
This is a refactor of the fix in facebook#27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In facebook#27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out facebook#27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.
acdlite added a commit to acdlite/react that referenced this pull request Aug 20, 2024
This is a refactor of the fix in facebook#27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In facebook#27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out facebook#27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.
acdlite added a commit to acdlite/react that referenced this pull request Aug 22, 2024
This is a refactor of the fix in facebook#27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In facebook#27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out facebook#27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.
acdlite added a commit to acdlite/react that referenced this pull request Aug 23, 2024
This is a refactor of the fix in facebook#27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In facebook#27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out facebook#27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.
acdlite added a commit that referenced this pull request Aug 23, 2024
This is a refactor of the fix in #27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In #27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out #27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.
github-actions bot pushed a commit that referenced this pull request Aug 23, 2024
This is a refactor of the fix in #27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In #27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out #27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.

DiffTrain build for commit ee7f675.
github-actions bot pushed a commit that referenced this pull request Aug 23, 2024
This is a refactor of the fix in #27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In #27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out #27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.

DiffTrain build for [ee7f675](ee7f675)
acdlite added a commit to acdlite/react that referenced this pull request Aug 27, 2024
This is a refactor of the fix in facebook#27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In facebook#27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out facebook#27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants