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

DevTools Suspense cache cleanup #22275

Merged
merged 3 commits into from
Sep 9, 2021

Conversation

bvaughn
Copy link
Contributor

@bvaughn bvaughn commented Sep 8, 2021

Fixed a few things I noticed while testing #22263.

Commits can be reviewed independently.

Brian Vaughn added 3 commits September 8, 2021 18:40
Use .catch() to handle errors in a chained promise. Previously certain errors would slip through without being caught, eventually resulting in the Suspense cache timeout (but not logging the underlying error).
I thought I had sufficiently guarded against this previously, but when testing the react-devtools-inline package with Webpack, I found another case that caused the hook names code to throw. I added a failing test mimicking this case, and then fixed the problem in loadSourceAndMetadata
@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Sep 8, 2021
Copy link
Contributor

@jstejada jstejada left a comment

Choose a reason for hiding this comment

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

thanks! i've noticed that sometimes parsing hook names can fail silently, or just without any indication of failure in the UI or logs.. would this change address that issue?

@bvaughn
Copy link
Contributor Author

bvaughn commented Sep 9, 2021

thanks! i've noticed that sometimes parsing hook names can fail silently, or just without any indication of failure in the UI or logs.. would this change address that issue?

Yes, that's the goal. Should at least log an error now (to the nested devtools console)

@bvaughn bvaughn merged commit 24c2e27 into facebook:main Sep 9, 2021
@bvaughn bvaughn deleted the devtools-suspense-cache-hadening branch September 9, 2021 13:28

const thenable = loadHookNamesFunction(hooksTree, fetchFileWithCaching);
thenable.then(onSuccess, onError);
if (typeof (thenable: any).catch === 'function') {
Copy link
Collaborator

@gaearon gaearon Sep 9, 2021

Choose a reason for hiding this comment

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

This does not look right to me. Can you elaborate on the reasoning for why this makes sense?

Normally, catch is not a part of the Thenable contract altogether. In Promises, .catch(onError) is a convenience that translates to .then(undefined, onError). So from what I see in this implementation, if thenable is a Promise, the consequence should be that onError runs twice:

thenable.then(onSuccess, onError)
thenable.then(undefined, onError)

I don't think this is what was intended.

Do you have a specific example case that you're trying to fix here? I suspect there's some other problem that was covered up, and maybe this accidentally fixes it, but it seems like a wrong fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As I understand it, catch should really only be necessary if an error was thrown inside of onSuccess or onError – but what I noticed yesterday when testing a source-map parsing problem (inside of the hooks/parseHookNames module) was that the onError callback wasn't being invoked, and the error was effectively being swallowed (until the timeout eventually fired).

I can try to repro this by backing out this change, if that would be helpful.

Copy link
Contributor Author

@bvaughn bvaughn Sep 9, 2021

Choose a reason for hiding this comment

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

I checked out bvaughn:devtools-dynamic-import-suspense-cache (#22263), and partially reverted this commit (24c2e27), and tried to repro the problem I saw yesterday and I'm not able. Kind of a head scratcher, but it tracks with my understanding of how .catch() works.

I can revert this specific change from this PR and leave the rest. Maybe @jstejada can weigh in if he sees another case where we aren't handling an error correctly in the cache?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted in 3c3f072

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Bit of follow-up.

After reverting that bit of the change, and using the test shell (with HMR on) for a little bit, I think I see the "uncaught error" issue I initially noticed. Digging in a little more, I think it actually comes from this code which doesn't pass the error handler:

inspectElementMutableSource({
bridge,
element,
path: null,
rendererID: ((rendererID: any): number),
}).then(
([
inspectedElement: InspectedElementFrontend,
responseType: InspectedElementResponseType,
]) => {
if (responseType === 'full-data') {
startTransition(() => {
const [key, value] = createCacheSeed(element, inspectedElement);
refresh(key, value);
});
}
},
);

So I think this was my mistake. Thanks for questioning this.

Copy link
Contributor

Choose a reason for hiding this comment

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

not sure if related, but yes i am planning to look into a case where we seemed to not handle an error, will report back as to whether it's related to this or not

Copy link
Collaborator

Choose a reason for hiding this comment

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

As I understand it, catch should really only be necessary if an error was thrown inside of onSuccess or onError

So I think it’s okay (and intentional) not to catch errors in these, just like React doesn’t. Because they should have the minimal logic that sets the values in the cache and have no reason to throw. If they do throw then that’s a bug in the cache, which should be surfaced as unhandled.

bvaughn pushed a commit that referenced this pull request Sep 9, 2021
Reverts part of #22275 (adding .catch() to Thenables in Suspense caches) in response to #22275 (comment).

After taking another look with fresh eyes, I think I see the "uncaught error" issue I initially noticed was in checkForUpdate() (which did not pass an error handler to .then)
zhengjitf pushed a commit to zhengjitf/react that referenced this pull request Apr 15, 2022
zhengjitf pushed a commit to zhengjitf/react that referenced this pull request Apr 15, 2022
Reverts part of facebook#22275 (adding .catch() to Thenables in Suspense caches) in response to facebook#22275 (comment).

After taking another look with fresh eyes, I think I see the "uncaught error" issue I initially noticed was in checkForUpdate() (which did not pass an error handler to .then)
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.

5 participants