Skip to content

Commit 6760039

Browse files
committed
Wrap try-catch directly around each user function
This moves the try-catch from around each fiber's mutation phase to direclty around each user function (effect function, callback, etc). We already do this when unmounting because if one unmount function errors, we still need to call all the others so they can clean up their resources. Previously we didn't bother to do this for anything but unmount, because if a mount effect throws, we're going to delete that whole tree anyway. But now that we're switching from an iterative loop to a recursive one, we don't want every call frame on the stack to have a try-catch, since the error handling requires additional memory. Wrapping every user function is a bit tedious, but it's better for performance. Many of them already had try blocks around them already.
1 parent 3657f7c commit 6760039

File tree

2 files changed

+228
-116
lines changed

2 files changed

+228
-116
lines changed

packages/react-reconciler/src/ReactFiberCommitWork.new.js

Lines changed: 114 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,12 +1077,15 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) {
10771077
if (node.tag === HostComponent) {
10781078
if (hostSubtreeRoot === null) {
10791079
hostSubtreeRoot = node;
1080-
1081-
const instance = node.stateNode;
1082-
if (isHidden) {
1083-
hideInstance(instance);
1084-
} else {
1085-
unhideInstance(node.stateNode, node.memoizedProps);
1080+
try {
1081+
const instance = node.stateNode;
1082+
if (isHidden) {
1083+
hideInstance(instance);
1084+
} else {
1085+
unhideInstance(node.stateNode, node.memoizedProps);
1086+
}
1087+
} catch (error) {
1088+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
10861089
}
10871090
}
10881091
} else if (node.tag === HostText) {
@@ -1938,11 +1941,7 @@ function commitMutationEffects_complete(root: FiberRoot, lanes: Lanes) {
19381941
while (nextEffect !== null) {
19391942
const fiber = nextEffect;
19401943
setCurrentDebugFiberInDEV(fiber);
1941-
try {
1942-
commitMutationEffectsOnFiber(fiber, root, lanes);
1943-
} catch (error) {
1944-
captureCommitPhaseError(fiber, fiber.return, error);
1945-
}
1944+
commitMutationEffectsOnFiber(fiber, root, lanes);
19461945
resetCurrentDebugFiberInDEV();
19471946

19481947
const sibling = fiber.sibling;
@@ -1975,12 +1974,19 @@ function commitMutationEffectsOnFiber(
19751974
commitReconciliationEffects(finishedWork);
19761975

19771976
if (flags & Update) {
1978-
commitHookEffectListUnmount(
1979-
HookInsertion | HookHasEffect,
1980-
finishedWork,
1981-
finishedWork.return,
1982-
);
1983-
commitHookEffectListMount(HookInsertion | HookHasEffect, finishedWork);
1977+
try {
1978+
commitHookEffectListUnmount(
1979+
HookInsertion | HookHasEffect,
1980+
finishedWork,
1981+
finishedWork.return,
1982+
);
1983+
commitHookEffectListMount(
1984+
HookInsertion | HookHasEffect,
1985+
finishedWork,
1986+
);
1987+
} catch (error) {
1988+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
1989+
}
19841990
// Layout effects are destroyed during the mutation phase so that all
19851991
// destroy functions for all fibers are called before any create functions.
19861992
// This prevents sibling component effects from interfering with each other,
@@ -1998,15 +2004,20 @@ function commitMutationEffectsOnFiber(
19982004
finishedWork,
19992005
finishedWork.return,
20002006
);
2001-
} finally {
2002-
recordLayoutEffectDuration(finishedWork);
2007+
} catch (error) {
2008+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
20032009
}
2010+
recordLayoutEffectDuration(finishedWork);
20042011
} else {
2005-
commitHookEffectListUnmount(
2006-
HookLayout | HookHasEffect,
2007-
finishedWork,
2008-
finishedWork.return,
2009-
);
2012+
try {
2013+
commitHookEffectListUnmount(
2014+
HookLayout | HookHasEffect,
2015+
finishedWork,
2016+
finishedWork.return,
2017+
);
2018+
} catch (error) {
2019+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2020+
}
20102021
}
20112022
}
20122023
return;
@@ -2016,7 +2027,7 @@ function commitMutationEffectsOnFiber(
20162027

20172028
if (flags & Ref) {
20182029
if (current !== null) {
2019-
commitDetachRef(current);
2030+
safelyDetachRef(current, current.return);
20202031
}
20212032
}
20222033
return;
@@ -2026,13 +2037,17 @@ function commitMutationEffectsOnFiber(
20262037

20272038
if (flags & Ref) {
20282039
if (current !== null) {
2029-
commitDetachRef(current);
2040+
safelyDetachRef(current, current.return);
20302041
}
20312042
}
20322043
if (supportsMutation) {
20332044
if (flags & ContentReset) {
20342045
const instance: Instance = finishedWork.stateNode;
2035-
resetTextContent(instance);
2046+
try {
2047+
resetTextContent(instance);
2048+
} catch (error) {
2049+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2050+
}
20362051
}
20372052

20382053
if (flags & Update) {
@@ -2050,14 +2065,22 @@ function commitMutationEffectsOnFiber(
20502065
const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);
20512066
finishedWork.updateQueue = null;
20522067
if (updatePayload !== null) {
2053-
commitUpdate(
2054-
instance,
2055-
updatePayload,
2056-
type,
2057-
oldProps,
2058-
newProps,
2059-
finishedWork,
2060-
);
2068+
try {
2069+
commitUpdate(
2070+
instance,
2071+
updatePayload,
2072+
type,
2073+
oldProps,
2074+
newProps,
2075+
finishedWork,
2076+
);
2077+
} catch (error) {
2078+
captureCommitPhaseError(
2079+
finishedWork,
2080+
finishedWork.return,
2081+
error,
2082+
);
2083+
}
20612084
}
20622085
}
20632086
}
@@ -2083,7 +2106,12 @@ function commitMutationEffectsOnFiber(
20832106
// this case.
20842107
const oldText: string =
20852108
current !== null ? current.memoizedProps : newText;
2086-
commitTextUpdate(textInstance, oldText, newText);
2109+
2110+
try {
2111+
commitTextUpdate(textInstance, oldText, newText);
2112+
} catch (error) {
2113+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2114+
}
20872115
}
20882116
}
20892117
return;
@@ -2093,24 +2121,28 @@ function commitMutationEffectsOnFiber(
20932121

20942122
// TODO: Add a flag check and move to passive phase. Luna's PR fixes this.
20952123
if (enableTransitionTracing) {
2096-
const state = finishedWork.memoizedState;
2097-
const transitions = state.transitions;
2098-
if (transitions !== null) {
2099-
transitions.forEach(transition => {
2100-
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
2101-
addTransitionStartCallbackToPendingTransition({
2102-
transitionName: transition.name,
2103-
startTime: transition.startTime,
2104-
});
2105-
2106-
addTransitionCompleteCallbackToPendingTransition({
2107-
transitionName: transition.name,
2108-
startTime: transition.startTime,
2124+
try {
2125+
const state = finishedWork.memoizedState;
2126+
const transitions = state.transitions;
2127+
if (transitions !== null) {
2128+
transitions.forEach(transition => {
2129+
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
2130+
addTransitionStartCallbackToPendingTransition({
2131+
transitionName: transition.name,
2132+
startTime: transition.startTime,
2133+
});
2134+
2135+
addTransitionCompleteCallbackToPendingTransition({
2136+
transitionName: transition.name,
2137+
startTime: transition.startTime,
2138+
});
21092139
});
2110-
});
21112140

2112-
clearTransitionsForLanes(root, lanes);
2113-
state.transitions = null;
2141+
clearTransitionsForLanes(root, lanes);
2142+
state.transitions = null;
2143+
}
2144+
} catch (error) {
2145+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
21142146
}
21152147
}
21162148

@@ -2119,14 +2151,26 @@ function commitMutationEffectsOnFiber(
21192151
if (current !== null) {
21202152
const prevRootState: RootState = current.memoizedState;
21212153
if (prevRootState.isDehydrated) {
2122-
commitHydratedContainer(root.containerInfo);
2154+
try {
2155+
commitHydratedContainer(root.containerInfo);
2156+
} catch (error) {
2157+
captureCommitPhaseError(
2158+
finishedWork,
2159+
finishedWork.return,
2160+
error,
2161+
);
2162+
}
21232163
}
21242164
}
21252165
}
21262166
if (supportsPersistence) {
21272167
const containerInfo = root.containerInfo;
21282168
const pendingChildren = root.pendingChildren;
2129-
replaceContainerChildren(containerInfo, pendingChildren);
2169+
try {
2170+
replaceContainerChildren(containerInfo, pendingChildren);
2171+
} catch (error) {
2172+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2173+
}
21302174
}
21312175
}
21322176
return;
@@ -2139,7 +2183,11 @@ function commitMutationEffectsOnFiber(
21392183
const portal = finishedWork.stateNode;
21402184
const containerInfo = portal.containerInfo;
21412185
const pendingChildren = portal.pendingChildren;
2142-
replaceContainerChildren(containerInfo, pendingChildren);
2186+
try {
2187+
replaceContainerChildren(containerInfo, pendingChildren);
2188+
} catch (error) {
2189+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2190+
}
21432191
}
21442192
}
21452193
return;
@@ -2159,7 +2207,11 @@ function commitMutationEffectsOnFiber(
21592207
}
21602208
}
21612209
if (flags & Update) {
2162-
commitSuspenseCallback(finishedWork);
2210+
try {
2211+
commitSuspenseCallback(finishedWork);
2212+
} catch (error) {
2213+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2214+
}
21632215
attachSuspenseRetryListeners(finishedWork);
21642216
}
21652217
return;
@@ -2216,7 +2268,7 @@ function commitMutationEffectsOnFiber(
22162268
// TODO: This is a temporary solution that allowed us to transition away
22172269
// from React Flare on www.
22182270
if (flags & Ref) {
2219-
commitAttachRef(finishedWork);
2271+
safelyAttachRef(finishedWork, finishedWork.return);
22202272
}
22212273
if (flags & Update) {
22222274
const scopeInstance = finishedWork.stateNode;
@@ -2237,7 +2289,11 @@ function commitReconciliationEffects(finishedWork: Fiber) {
22372289
// before the effects on this fiber have fired.
22382290
const flags = finishedWork.flags;
22392291
if (flags & Placement) {
2240-
commitPlacement(finishedWork);
2292+
try {
2293+
commitPlacement(finishedWork);
2294+
} catch (error) {
2295+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2296+
}
22412297
// Clear the "placement" from effect tag so that we know that this is
22422298
// inserted, before any life-cycles like componentDidMount gets called.
22432299
// TODO: findDOMNode doesn't rely on this any more but isMounted does

0 commit comments

Comments
 (0)