Skip to content

[Flight] Ignore async stack frames when determining if a Promise was created from user space #33739

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

Merged
merged 3 commits into from
Jul 9, 2025

Conversation

sebmarkbage
Copy link
Collaborator

We use the stack of a Promise as the start of the I/O instead of the actual I/O since that can symbolize the start of the operation even if the actual I/O is batched, deduped or pooled. It can also group multiple I/O operations into one.

We want the deepest possible Promise since otherwise it would just be the Component's Promise.

However, we don't really need deeper than the boundary between first party and third party. We can't just take the outer most that has third party things on the stack though because third party can have callbacks into first party and then we want the inner one. So we take the inner most Promise that depends on I/O that has a first party stack on it.

The realization is that for the purposes of determining whether we have a first party stack we need to ignore async stack frames. They can appear on the stack when we resume third party code inside a resumption frame of a first party stack.

Screenshot 2025-07-08 at 6 34 25 PM

@sebmarkbage sebmarkbage requested a review from eps1lon July 8, 2025 23:09
@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label Jul 8, 2025
@react-sizebot
Copy link

react-sizebot commented Jul 8, 2025

Comparing: a7a1165...74d3174

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.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 530.70 kB 530.70 kB = 93.70 kB 93.70 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB +0.05% 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 655.25 kB 655.25 kB = 115.40 kB 115.40 kB
facebook-www/ReactDOM-prod.classic.js = 675.13 kB 675.13 kB = 118.75 kB 118.75 kB
facebook-www/ReactDOM-prod.modern.js = 665.56 kB 665.56 kB = 117.12 kB 117.12 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-server/cjs/react-server-flight.development.js +0.25% 126.37 kB 126.69 kB +0.33% 23.01 kB 23.08 kB
oss-stable/react-server/cjs/react-server-flight.development.js +0.25% 126.37 kB 126.69 kB +0.33% 23.01 kB 23.08 kB
oss-experimental/react-server/cjs/react-server-flight.development.js +0.23% 134.97 kB 135.28 kB +0.30% 24.55 kB 24.62 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +0.22% 196.71 kB 197.15 kB +0.29% 36.28 kB 36.39 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +0.22% 202.67 kB 203.11 kB +0.28% 36.96 kB 37.07 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.unbundled.development.js +0.21% 209.44 kB 209.88 kB +0.28% 38.12 kB 38.22 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +0.21% 210.59 kB 211.03 kB +0.28% 38.41 kB 38.51 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +0.21% 210.65 kB 211.09 kB +0.28% 38.42 kB 38.53 kB

Generated by 🚫 dangerJS against 74d3174

@@ -0,0 +1,9 @@
export async function sdkMethod(input, init) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is a bit weird because it's using an async function without actually awaiting anywhere. You might think of optimizing it to not be an async function and just return the Promise.

Unfortunately, then it doesn't get any name at all and no stack for the I/O (just the await). Because now there's no Promise with a good stack around it.

Ideally we'd probably use the .then call as the best available stack for the I/O but not sure how that makes sense since it's not the cause spawning the I/O. Maybe it's really the Promise that it is awaiting that's the best possible Promise in that case. I.e. the first fetch. But I'm not going to address that now.

@sebmarkbage sebmarkbage merged commit 150f022 into facebook:main Jul 9, 2025
241 checks passed
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