Skip to content

Commit 2ed6229

Browse files
committed
Use invokeGuardedCallback in place of Fiber try-catch blocks
Only in DEV. In production, continue using a local try-catch.
1 parent f4ad51d commit 2ed6229

File tree

2 files changed

+68
-31
lines changed

2 files changed

+68
-31
lines changed

src/renderers/shared/fiber/ReactFiberCommitWork.js

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ var {
2626
} = ReactTypeOfWork;
2727
var { commitCallbacks } = require('ReactFiberUpdateQueue');
2828
var { onCommitUnmount } = require('ReactFiberDevToolsHook');
29+
var { invokeGuardedCallback } = require('ReactErrorUtils');
2930

3031
var {
3132
Placement,
@@ -54,22 +55,35 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
5455

5556
// Capture errors so they don't interrupt unmounting.
5657
function safelyCallComponentWillUnmount(current, instance) {
57-
try {
58-
instance.componentWillUnmount();
59-
} catch (error) {
60-
captureError(current, error);
58+
if (__DEV__) {
59+
const unmountError = invokeGuardedCallback(null, instance.componentWillUnmount, instance);
60+
if (unmountError) {
61+
captureError(current, unmountError);
62+
}
63+
} else {
64+
try {
65+
instance.componentWillUnmount();
66+
} catch (unmountError) {
67+
captureError(current, unmountError);
68+
}
6169
}
6270
}
6371

64-
// Capture errors so they don't interrupt unmounting.
6572
function safelyDetachRef(current : Fiber) {
66-
try {
67-
const ref = current.ref;
68-
if (ref !== null) {
69-
ref(null);
73+
const ref = current.ref;
74+
if (ref !== null) {
75+
if (__DEV__) {
76+
const refError = invokeGuardedCallback(null, ref, null, null);
77+
if (refError !== null) {
78+
captureError(current, refError);
79+
}
80+
} else {
81+
try {
82+
ref(null);
83+
} catch (refError) {
84+
captureError(current, refError);
85+
}
7086
}
71-
} catch (error) {
72-
captureError(current, error);
7387
}
7488
}
7589

src/renderers/shared/fiber/ReactFiberScheduler.js

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ var {
3535
getStackAddendumByWorkInProgressFiber,
3636
} = require('ReactComponentTreeHook');
3737
var { logCapturedError } = require('ReactFiberErrorLogger');
38+
var { invokeGuardedCallback } = require('ReactErrorUtils');
3839

3940
var ReactFiberBeginWork = require('ReactFiberBeginWork');
4041
var ReactFiberCompleteWork = require('ReactFiberCompleteWork');
@@ -144,6 +145,9 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
144145
// Keeps track of whether we're currently in a work loop.
145146
let isPerformingWork : boolean = false;
146147

148+
// Keeps track of whether the current deadline has expired.
149+
let deadlineHasExpired : boolean = false;
150+
147151
// Keeps track of whether we should should batch sync updates.
148152
let isBatchingUpdates : boolean = false;
149153

@@ -394,9 +398,17 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
394398
// ref unmounts.
395399
nextEffect = firstEffect;
396400
while (nextEffect !== null) {
397-
try {
398-
commitAllHostEffects(finishedWork);
399-
} catch (error) {
401+
let error = null;
402+
if (__DEV__) {
403+
error = invokeGuardedCallback(null, commitAllHostEffects, null, finishedWork);
404+
} else {
405+
try {
406+
commitAllHostEffects(finishedWork);
407+
} catch (e) {
408+
error = e;
409+
}
410+
}
411+
if (error !== null) {
400412
invariant(
401413
nextEffect !== null,
402414
'Should have next effect. This error is likely caused by a bug ' +
@@ -424,9 +436,17 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
424436
// This pass also triggers any renderer-specific initial effects.
425437
nextEffect = firstEffect;
426438
while (nextEffect !== null) {
427-
try {
428-
commitAllLifeCycles(finishedWork, nextEffect);
429-
} catch (error) {
439+
let error = null;
440+
if (__DEV__) {
441+
error = invokeGuardedCallback(null, commitAllLifeCycles, null, finishedWork);
442+
} else {
443+
try {
444+
commitAllLifeCycles(finishedWork);
445+
} catch (e) {
446+
error = e;
447+
}
448+
}
449+
if (error !== null) {
430450
invariant(
431451
nextEffect !== null,
432452
'Should have next effect. This error is likely caused by a bug ' +
@@ -655,7 +675,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
655675
}
656676
}
657677

658-
function workLoop(priorityLevel, deadline : Deadline | null, deadlineHasExpired : boolean) : boolean {
678+
function workLoop(priorityLevel, deadline : Deadline | null) {
659679
// Clear any errors.
660680
clearErrors();
661681

@@ -723,8 +743,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
723743
if (hostRootTimeMarker) {
724744
console.timeEnd(hostRootTimeMarker);
725745
}
726-
727-
return deadlineHasExpired;
728746
}
729747

730748
function performWork(priorityLevel : PriorityLevel, deadline : Deadline | null) {
@@ -735,7 +753,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
735753
);
736754
isPerformingWork = true;
737755
const isPerformingDeferredWork = Boolean(deadline);
738-
let deadlineHasExpired = false;
739756

740757
// This outer loop exists so that we can restart the work loop after
741758
// catching an error. It also lets us flush Task work at the end of a
@@ -756,18 +773,25 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
756773
// Nothing in performWork should be allowed to throw. All unsafe
757774
// operations must happen within workLoop, which is extracted to a
758775
// separate function so that it can be optimized by the JS engine.
759-
try {
760-
priorityContextBeforeReconciliation = priorityContext;
761-
priorityContext = nextPriorityLevel;
762-
deadlineHasExpired = workLoop(priorityLevel, deadline, deadlineHasExpired);
763-
} catch (error) {
776+
priorityContextBeforeReconciliation = priorityContext;
777+
let error = null;
778+
if (__DEV__) {
779+
error = invokeGuardedCallback(null, workLoop, null, priorityLevel, deadline);
780+
} else {
781+
try {
782+
workLoop(priorityLevel, deadline);
783+
} catch (e) {
784+
error = e;
785+
}
786+
}
787+
// Reset the priority context to its value before reconcilation.
788+
priorityContext = priorityContextBeforeReconciliation;
789+
790+
if (error !== null) {
764791
// We caught an error during either the begin or complete phases.
765792
const failedWork = nextUnitOfWork;
766793

767794
if (failedWork !== null) {
768-
// Reset the priority context to its value before reconciliation.
769-
priorityContext = priorityContextBeforeReconciliation;
770-
771795
// "Capture" the error by finding the nearest boundary. If there is no
772796
// error boundary, the nearest host container acts as one. If
773797
// captureError returns null, the error was intentionally ignored.
@@ -798,8 +822,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
798822
// inside resetAfterCommit.
799823
fatalError = error;
800824
}
801-
} finally {
802-
priorityContext = priorityContextBeforeReconciliation;
803825
}
804826

805827
// Stop performing work
@@ -842,6 +864,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
842864

843865
// We're done performing work. Time to clean up.
844866
isPerformingWork = false;
867+
deadlineHasExpired = false;
845868
fatalError = null;
846869
firstUncaughtError = null;
847870
capturedErrors = null;

0 commit comments

Comments
 (0)