@samitouri / QOS-React-2 / commits / d1bb4d851f

Profiler: Include ref callbacks in onCommit duration (#20060)

Brian Vaughn committed Oct 20, 2020 at 14:35 UTC d1bb4d851f4956cb64ad0ae1867153c23409f971
3 files changed +163 -8
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+54 -4
@@ -194,14 +194,38 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber) {
194 if (ref !== null) {
195 if (typeof ref === 'function') {
196 if (__DEV__) {
197 - invokeGuardedCallback(null, ref, null, null);
197 + if (
198 + enableProfilerTimer &&
199 + enableProfilerCommitHooks &&
200 + current.mode & ProfileMode
201 + ) {
202 + startLayoutEffectTimer();
203 + invokeGuardedCallback(null, ref, null, null);
204 + recordLayoutEffectDuration(current);
205 + } else {
206 + invokeGuardedCallback(null, ref, null, null);
207 + }
208 +
209 if (hasCaughtError()) {
210 const refError = clearCaughtError();
211 captureCommitPhaseError(current, nearestMountedAncestor, refError);
212 }
213 } else {
214 try {
204 - ref(null);
215 + if (
216 + enableProfilerTimer &&
217 + enableProfilerCommitHooks &&
218 + current.mode & ProfileMode
219 + ) {
220 + try {
221 + startLayoutEffectTimer();
222 + ref(null);
223 + } finally {
224 + recordLayoutEffectDuration(current);
225 + }
226 + } else {
227 + ref(null);
228 + }
229 } catch (refError) {
230 captureCommitPhaseError(current, nearestMountedAncestor, refError);
231 }
@@ -965,7 +989,20 @@ function commitAttachRef(finishedWork: Fiber) {
989 instanceToUse = instance;
990 }
991 if (typeof ref === 'function') {
968 - ref(instanceToUse);
992 + if (
993 + enableProfilerTimer &&
994 + enableProfilerCommitHooks &&
995 + finishedWork.mode & ProfileMode
996 + ) {
997 + try {
998 + startLayoutEffectTimer();
999 + ref(instanceToUse);
1000 + } finally {
1001 + recordLayoutEffectDuration(finishedWork);
1002 + }
1003 + } else {
1004 + ref(instanceToUse);
1005 + }
1006 } else {
1007 if (__DEV__) {
1008 if (!ref.hasOwnProperty('current')) {
@@ -986,7 +1023,20 @@ function commitDetachRef(current: Fiber) {
1023 const currentRef = current.ref;
1024 if (currentRef !== null) {
1025 if (typeof currentRef === 'function') {
989 - currentRef(null);
1026 + if (
1027 + enableProfilerTimer &&
1028 + enableProfilerCommitHooks &&
1029 + current.mode & ProfileMode
1030 + ) {
1031 + try {
1032 + startLayoutEffectTimer();
1033 + currentRef(null);
1034 + } finally {
1035 + recordLayoutEffectDuration(current);
1036 + }
1037 + } else {
1038 + currentRef(null);
1039 + }
1040 } else {
1041 currentRef.current = null;
1042 }
packages/react-reconciler/src/ReactFiberCommitWork.old.js
+54 -4
@@ -180,14 +180,38 @@ function safelyDetachRef(current: Fiber) {
180 if (ref !== null) {
181 if (typeof ref === 'function') {
182 if (__DEV__) {
183 - invokeGuardedCallback(null, ref, null, null);
183 + if (
184 + enableProfilerTimer &&
185 + enableProfilerCommitHooks &&
186 + current.mode & ProfileMode
187 + ) {
188 + startLayoutEffectTimer();
189 + invokeGuardedCallback(null, ref, null, null);
190 + recordLayoutEffectDuration(current);
191 + } else {
192 + invokeGuardedCallback(null, ref, null, null);
193 + }
194 +
195 if (hasCaughtError()) {
196 const refError = clearCaughtError();
197 captureCommitPhaseError(current, refError);
198 }
199 } else {
200 try {
190 - ref(null);
201 + if (
202 + enableProfilerTimer &&
203 + enableProfilerCommitHooks &&
204 + current.mode & ProfileMode
205 + ) {
206 + try {
207 + startLayoutEffectTimer();
208 + ref(null);
209 + } finally {
210 + recordLayoutEffectDuration(current);
211 + }
212 + } else {
213 + ref(null);
214 + }
215 } catch (refError) {
216 captureCommitPhaseError(current, refError);
217 }
@@ -832,7 +856,20 @@ function commitAttachRef(finishedWork: Fiber) {
856 instanceToUse = instance;
857 }
858 if (typeof ref === 'function') {
835 - ref(instanceToUse);
859 + if (
860 + enableProfilerTimer &&
861 + enableProfilerCommitHooks &&
862 + finishedWork.mode & ProfileMode
863 + ) {
864 + try {
865 + startLayoutEffectTimer();
866 + ref(instanceToUse);
867 + } finally {
868 + recordLayoutEffectDuration(finishedWork);
869 + }
870 + } else {
871 + ref(instanceToUse);
872 + }
873 } else {
874 if (__DEV__) {
875 if (!ref.hasOwnProperty('current')) {
@@ -853,7 +890,20 @@ function commitDetachRef(current: Fiber) {
890 const currentRef = current.ref;
891 if (currentRef !== null) {
892 if (typeof currentRef === 'function') {
856 - currentRef(null);
893 + if (
894 + enableProfilerTimer &&
895 + enableProfilerCommitHooks &&
896 + current.mode & ProfileMode
897 + ) {
898 + try {
899 + startLayoutEffectTimer();
900 + currentRef(null);
901 + } finally {
902 + recordLayoutEffectDuration(current);
903 + }
904 + } else {
905 + currentRef(null);
906 + }
907 } else {
908 currentRef.current = null;
909 }
packages/react/src/__tests__/ReactProfiler-test.internal.js
+55
@@ -1491,6 +1491,61 @@ describe('Profiler', () => {
1491 expect(call[4]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events
1492 });
1493
1494 + it('should include time spent in ref callbacks', () => {
1495 + const callback = jest.fn();
1496 +
1497 + const refSetter = ref => {
1498 + if (ref !== null) {
1499 + Scheduler.unstable_advanceTime(10);
1500 + } else {
1501 + Scheduler.unstable_advanceTime(100);
1502 + }
1503 + };
1504 +
1505 + class ClassComponent extends React.Component {
1506 + render() {
1507 + return null;
1508 + }
1509 + }
1510 +
1511 + const Component = () => {
1512 + Scheduler.unstable_advanceTime(1000);
1513 + return <ClassComponent ref={refSetter} />;
1514 + };
1515 +
1516 + Scheduler.unstable_advanceTime(1);
1517 +
1518 + const renderer = ReactTestRenderer.create(
1519 + <React.Profiler id="root" onCommit={callback}>
1520 + <Component />
1521 + </React.Profiler>,
1522 + );
1523 +
1524 + expect(callback).toHaveBeenCalledTimes(1);
1525 +
1526 + let call = callback.mock.calls[0];
1527 +
1528 + expect(call).toHaveLength(enableSchedulerTracing ? 5 : 4);
1529 + expect(call[0]).toBe('root');
1530 + expect(call[1]).toBe('mount');
1531 + expect(call[2]).toBe(10); // durations
1532 + expect(call[3]).toBe(1001); // commit start time (before mutations or effects)
1533 +
1534 + callback.mockClear();
1535 +
1536 + renderer.update(<React.Profiler id="root" onCommit={callback} />);
1537 +
1538 + expect(callback).toHaveBeenCalledTimes(1);
1539 +
1540 + call = callback.mock.calls[0];
1541 +
1542 + expect(call).toHaveLength(enableSchedulerTracing ? 5 : 4);
1543 + expect(call[0]).toBe('root');
1544 + expect(call[1]).toBe('update');
1545 + expect(call[2]).toBe(100); // durations
1546 + expect(call[3]).toBe(1011); // commit start time (before mutations or effects)
1547 + });
1548 +
1549 it('should bubble time spent in layout effects to higher profilers', () => {
1550 const callback = jest.fn();
1551