Skip to content

Commit 53d0794

Browse files
authored
[Fiber] Assign implicit debug info to used thenables (#34146)
Similar to #34137 but for Promises. This lets us pick up the debug info from a raw Promise as a child which is not covered by `_debugThenables`. Currently ChildFiber doesn't stash its thenables so we can't pick them up from devtools after the fact without some debug info added to the parent. It also lets us track some approximate start/end time of use():ed promises based on the first time we saw this particular Promise.
1 parent 34ce3ac commit 53d0794

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

packages/react-reconciler/src/ReactFiberThenable.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
PendingThenable,
1313
FulfilledThenable,
1414
RejectedThenable,
15+
ReactIOInfo,
1516
} from 'shared/ReactTypes';
1617

1718
import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy';
@@ -22,6 +23,8 @@ import {getWorkInProgressRoot} from './ReactFiberWorkLoop';
2223

2324
import ReactSharedInternals from 'shared/ReactSharedInternals';
2425

26+
import {enableAsyncDebugInfo} from 'shared/ReactFeatureFlags';
27+
2528
import noop from 'shared/noop';
2629

2730
opaque type ThenableStateDev = {
@@ -154,6 +157,33 @@ export function trackUsedThenable<T>(
154157
}
155158
}
156159

160+
if (__DEV__ && enableAsyncDebugInfo && thenable._debugInfo === undefined) {
161+
// In DEV mode if the thenable that we observed had no debug info, then we add
162+
// an inferred debug info so that we're able to track its potential I/O uniquely.
163+
// We don't know the real start time since the I/O could have started much
164+
// earlier and this could even be a cached Promise. Could be misleading.
165+
const startTime = performance.now();
166+
const displayName = thenable.displayName;
167+
const ioInfo: ReactIOInfo = {
168+
name: typeof displayName === 'string' ? displayName : 'Promise',
169+
start: startTime,
170+
end: startTime,
171+
value: (thenable: any),
172+
// We don't know the requesting owner nor stack.
173+
};
174+
// We can infer the await owner/stack lazily from where this promise ends up
175+
// used. It can be used in more than one place so we can't assign it here.
176+
thenable._debugInfo = [{awaited: ioInfo}];
177+
// Track when we resolved the Promise as the approximate end time.
178+
if (thenable.status !== 'fulfilled' && thenable.status !== 'rejected') {
179+
const trackEndTime = () => {
180+
// $FlowFixMe[cannot-write]
181+
ioInfo.end = performance.now();
182+
};
183+
thenable.then(trackEndTime, trackEndTime);
184+
}
185+
}
186+
157187
// We use an expando to track the status and result of a thenable so that we
158188
// can synchronously unwrap the value. Think of this as an extension of the
159189
// Promise API, or a custom interface that is a superset of Thenable.

0 commit comments

Comments
 (0)