Skip to content

Conversation

@sebmarkbage
Copy link
Collaborator

For "render" and "commit" phases we don't give any specific stack atm. This tries to always provide something useful to say the cause of the render.

For normal renders this will now show the same thing as the "Event" and "Update" entries already showed. We stash the task that was used for those and use them throughout the render and commit phases.

For Suspense (Retry lane) and Idle (Offscreen lane), we don't have any updates. Instead for those there's a component that left work behind in previous passes. For those I use the debugTask of the <Suspense> or <Activity> boundary to indicate that this was the root of the render.

Similarly when an Action is invoked on a <form action={...}> component using the built-in submit handler, there's no actionable stack in user space that called it. So we use the stack of the JSX for the form instead.

@sebmarkbage sebmarkbage requested a review from hoxyq August 7, 2025 03:21
@meta-cla meta-cla bot added the CLA Signed label Aug 7, 2025
@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label Aug 7, 2025
…ndary that caused a Retry or Offscreen lane

Suspense and Idle tracks don't have their own update causes. The component is the cause.
E.g. the <form> jsx callsite if it was a built-in action prop.
@sebmarkbage sebmarkbage force-pushed the includecauseonrender branch from 4b7d35c to 6f2c7d7 Compare August 7, 2025 03:27
@sebmarkbage
Copy link
Collaborator Author

For all of these, it really sucks that Chrome shows the enclosing line instead of the actual line for async stacks.

These can cause it to jump to two rows but it should always be one row.
Comment on lines +809 to +811
if (endTime <= startTime) {
return;
}
Copy link
Contributor

@hoxyq hoxyq Aug 7, 2025

Choose a reason for hiding this comment

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

I see that you've added this check to the loggers, but what has changed so that you need to check this?

If I remember correctly, DevTools just won't show entries on a timeline, where endTime < startTime, but they would still be present in an exported json-file, which could be useful for debugging Perf tracks implementation.

And if endTime == startTime, are zero-width entries displayed on a timeline?

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 is unrelated to this PR but it's the same as the change I made here for some other ones:

b3f67f9

The problem is that they get logged as zero-width entries but those stack on top of whatever other entry is at the same time. Which causes the Scheduler track row to turn into a two row track instead of one and there's this little single pixel lines on the second line.

Ideally that track shouldn't even need to be expanded. It should be clickable while on a single line from the start.

? 'Update Blocked'
: 'Update',
isPingedUpdate
? 'Promise Resolved'
Copy link
Contributor

Choose a reason for hiding this comment

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

Not related to these changes, just thinking out loud.

"Promise Resolved" sounds like an instant event, just a timestamp, instead of a complete event, where you have start and end.

I can't really think of a better naming for this, just want to avoid users thinking that Scheduler was actually waiting for this Promise to be resolved and this was blocking work. Same can be said about Cascading Update, though.

What do you think about naming this something like "Idle... Promise Resolved" and "Idle... Cascading Update"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yea I don't like it neither. I also don't like "resolved" because it implies that the promise completed successfully but it can also be that it rejected.

Originally this track was called "Blocked" since it represents the time from when you called the update until it started rendering. I later changed it to "Update Blocked" only if it's a longer period. If it's short anyway then "Update" is basically an instant.

We could do something like "Promise Resolved but Blocked" but a bit long to fit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Internally we just called it "ping" but we don't publicly use that term anywhere. "Ping Blocked"

@sebmarkbage sebmarkbage merged commit 4c9c109 into facebook:main Aug 7, 2025
240 of 241 checks passed
github-actions bot pushed a commit that referenced this pull request Aug 7, 2025
…formance Track (#34123)

For "render" and "commit" phases we don't give any specific stack atm.
This tries to always provide something useful to say the cause of the
render.

For normal renders this will now show the same thing as the "Event" and
"Update" entries already showed. We stash the task that was used for
those and use them throughout the render and commit phases.

For Suspense (Retry lane) and Idle (Offscreen lane), we don't have any
updates. Instead for those there's a component that left work behind in
previous passes. For those I use the debugTask of the `<Suspense>` or
`<Activity>` boundary to indicate that this was the root of the render.

Similarly when an Action is invoked on a `<form action={...}>` component
using the built-in submit handler, there's no actionable stack in user
space that called it. So we use the stack of the JSX for the form
instead.

DiffTrain build for [4c9c109](4c9c109)
github-actions bot pushed a commit that referenced this pull request Aug 7, 2025
…formance Track (#34123)

For "render" and "commit" phases we don't give any specific stack atm.
This tries to always provide something useful to say the cause of the
render.

For normal renders this will now show the same thing as the "Event" and
"Update" entries already showed. We stash the task that was used for
those and use them throughout the render and commit phases.

For Suspense (Retry lane) and Idle (Offscreen lane), we don't have any
updates. Instead for those there's a component that left work behind in
previous passes. For those I use the debugTask of the `<Suspense>` or
`<Activity>` boundary to indicate that this was the root of the render.

Similarly when an Action is invoked on a `<form action={...}>` component
using the built-in submit handler, there's no actionable stack in user
space that called it. So we use the stack of the JSX for the form
instead.

DiffTrain build for [4c9c109](4c9c109)
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.

2 participants