Skip to content

Commit f9e6aef

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 bcc1b31 commit f9e6aef

File tree

2 files changed

+208
-96
lines changed

2 files changed

+208
-96
lines changed

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

Lines changed: 104 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,21 +1077,28 @@ 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) {
10891092
if (hostSubtreeRoot === null) {
1090-
const instance = node.stateNode;
1091-
if (isHidden) {
1092-
hideTextInstance(instance);
1093-
} else {
1094-
unhideTextInstance(instance, node.memoizedProps);
1093+
try {
1094+
const instance = node.stateNode;
1095+
if (isHidden) {
1096+
hideTextInstance(instance);
1097+
} else {
1098+
unhideTextInstance(instance, node.memoizedProps);
1099+
}
1100+
} catch (error) {
1101+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
10951102
}
10961103
}
10971104
} else if (
@@ -1938,11 +1945,7 @@ function commitMutationEffects_complete(root: FiberRoot, lanes: Lanes) {
19381945
while (nextEffect !== null) {
19391946
const fiber = nextEffect;
19401947
setCurrentDebugFiberInDEV(fiber);
1941-
try {
1942-
commitMutationEffectsOnFiber(fiber, root, lanes);
1943-
} catch (error) {
1944-
captureCommitPhaseError(fiber, fiber.return, error);
1945-
}
1948+
commitMutationEffectsOnFiber(fiber, root, lanes);
19461949
resetCurrentDebugFiberInDEV();
19471950

19481951
const sibling = fiber.sibling;
@@ -1975,12 +1978,19 @@ function commitMutationEffectsOnFiber(
19751978
commitReconciliationEffects(finishedWork);
19761979

19771980
if (flags & Update) {
1978-
commitHookEffectListUnmount(
1979-
HookInsertion | HookHasEffect,
1980-
finishedWork,
1981-
finishedWork.return,
1982-
);
1983-
commitHookEffectListMount(HookInsertion | HookHasEffect, finishedWork);
1981+
try {
1982+
commitHookEffectListUnmount(
1983+
HookInsertion | HookHasEffect,
1984+
finishedWork,
1985+
finishedWork.return,
1986+
);
1987+
commitHookEffectListMount(
1988+
HookInsertion | HookHasEffect,
1989+
finishedWork,
1990+
);
1991+
} catch (error) {
1992+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
1993+
}
19841994
// Layout effects are destroyed during the mutation phase so that all
19851995
// destroy functions for all fibers are called before any create functions.
19861996
// This prevents sibling component effects from interfering with each other,
@@ -1998,15 +2008,20 @@ function commitMutationEffectsOnFiber(
19982008
finishedWork,
19992009
finishedWork.return,
20002010
);
2001-
} finally {
2002-
recordLayoutEffectDuration(finishedWork);
2011+
} catch (error) {
2012+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
20032013
}
2014+
recordLayoutEffectDuration(finishedWork);
20042015
} else {
2005-
commitHookEffectListUnmount(
2006-
HookLayout | HookHasEffect,
2007-
finishedWork,
2008-
finishedWork.return,
2009-
);
2016+
try {
2017+
commitHookEffectListUnmount(
2018+
HookLayout | HookHasEffect,
2019+
finishedWork,
2020+
finishedWork.return,
2021+
);
2022+
} catch (error) {
2023+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2024+
}
20102025
}
20112026
}
20122027
return;
@@ -2016,7 +2031,7 @@ function commitMutationEffectsOnFiber(
20162031

20172032
if (flags & Ref) {
20182033
if (current !== null) {
2019-
commitDetachRef(current);
2034+
safelyDetachRef(current, current.return);
20202035
}
20212036
}
20222037
return;
@@ -2026,13 +2041,17 @@ function commitMutationEffectsOnFiber(
20262041

20272042
if (flags & Ref) {
20282043
if (current !== null) {
2029-
commitDetachRef(current);
2044+
safelyDetachRef(current, current.return);
20302045
}
20312046
}
20322047
if (supportsMutation) {
20332048
if (flags & ContentReset) {
20342049
const instance: Instance = finishedWork.stateNode;
2035-
resetTextContent(instance);
2050+
try {
2051+
resetTextContent(instance);
2052+
} catch (error) {
2053+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2054+
}
20362055
}
20372056

20382057
if (flags & Update) {
@@ -2050,14 +2069,22 @@ function commitMutationEffectsOnFiber(
20502069
const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);
20512070
finishedWork.updateQueue = null;
20522071
if (updatePayload !== null) {
2053-
commitUpdate(
2054-
instance,
2055-
updatePayload,
2056-
type,
2057-
oldProps,
2058-
newProps,
2059-
finishedWork,
2060-
);
2072+
try {
2073+
commitUpdate(
2074+
instance,
2075+
updatePayload,
2076+
type,
2077+
oldProps,
2078+
newProps,
2079+
finishedWork,
2080+
);
2081+
} catch (error) {
2082+
captureCommitPhaseError(
2083+
finishedWork,
2084+
finishedWork.return,
2085+
error,
2086+
);
2087+
}
20612088
}
20622089
}
20632090
}
@@ -2083,7 +2110,12 @@ function commitMutationEffectsOnFiber(
20832110
// this case.
20842111
const oldText: string =
20852112
current !== null ? current.memoizedProps : newText;
2086-
commitTextUpdate(textInstance, oldText, newText);
2113+
2114+
try {
2115+
commitTextUpdate(textInstance, oldText, newText);
2116+
} catch (error) {
2117+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2118+
}
20872119
}
20882120
}
20892121
return;
@@ -2096,14 +2128,26 @@ function commitMutationEffectsOnFiber(
20962128
if (current !== null) {
20972129
const prevRootState: RootState = current.memoizedState;
20982130
if (prevRootState.isDehydrated) {
2099-
commitHydratedContainer(root.containerInfo);
2131+
try {
2132+
commitHydratedContainer(root.containerInfo);
2133+
} catch (error) {
2134+
captureCommitPhaseError(
2135+
finishedWork,
2136+
finishedWork.return,
2137+
error,
2138+
);
2139+
}
21002140
}
21012141
}
21022142
}
21032143
if (supportsPersistence) {
21042144
const containerInfo = root.containerInfo;
21052145
const pendingChildren = root.pendingChildren;
2106-
replaceContainerChildren(containerInfo, pendingChildren);
2146+
try {
2147+
replaceContainerChildren(containerInfo, pendingChildren);
2148+
} catch (error) {
2149+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2150+
}
21072151
}
21082152
}
21092153
return;
@@ -2116,7 +2160,11 @@ function commitMutationEffectsOnFiber(
21162160
const portal = finishedWork.stateNode;
21172161
const containerInfo = portal.containerInfo;
21182162
const pendingChildren = portal.pendingChildren;
2119-
replaceContainerChildren(containerInfo, pendingChildren);
2163+
try {
2164+
replaceContainerChildren(containerInfo, pendingChildren);
2165+
} catch (error) {
2166+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2167+
}
21202168
}
21212169
}
21222170
return;
@@ -2136,7 +2184,11 @@ function commitMutationEffectsOnFiber(
21362184
}
21372185
}
21382186
if (flags & Update) {
2139-
commitSuspenseCallback(finishedWork);
2187+
try {
2188+
commitSuspenseCallback(finishedWork);
2189+
} catch (error) {
2190+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2191+
}
21402192
attachSuspenseRetryListeners(finishedWork);
21412193
}
21422194
return;
@@ -2194,9 +2246,9 @@ function commitMutationEffectsOnFiber(
21942246
// from React Flare on www.
21952247
if (flags & Ref) {
21962248
if (current !== null) {
2197-
commitDetachRef(current);
2249+
safelyDetachRef(finishedWork, finishedWork.return);
21982250
}
2199-
commitAttachRef(finishedWork);
2251+
safelyAttachRef(finishedWork, finishedWork.return);
22002252
}
22012253
if (flags & Update) {
22022254
const scopeInstance = finishedWork.stateNode;
@@ -2217,7 +2269,11 @@ function commitReconciliationEffects(finishedWork: Fiber) {
22172269
// before the effects on this fiber have fired.
22182270
const flags = finishedWork.flags;
22192271
if (flags & Placement) {
2220-
commitPlacement(finishedWork);
2272+
try {
2273+
commitPlacement(finishedWork);
2274+
} catch (error) {
2275+
captureCommitPhaseError(finishedWork, finishedWork.return, error);
2276+
}
22212277
// Clear the "placement" from effect tag so that we know that this is
22222278
// inserted, before any life-cycles like componentDidMount gets called.
22232279
// TODO: findDOMNode doesn't rely on this any more but isMounted does

0 commit comments

Comments
 (0)