@@ -75,7 +75,14 @@ import {startPhaseTimer, stopPhaseTimer} from './ReactDebugFiberPerf';
75
75
import { getStackByFiberInDevAndProd } from './ReactCurrentFiber' ;
76
76
import { logCapturedError } from './ReactFiberErrorLogger' ;
77
77
import { resolveDefaultProps } from './ReactFiberLazyComponent' ;
78
- import { getCommitTime } from './ReactProfilerTimer' ;
78
+ import {
79
+ getCommitTime ,
80
+ recordLayoutEffectDuration ,
81
+ recordPassiveEffectDuration ,
82
+ startLayoutEffectTimer ,
83
+ startPassiveEffectTimer ,
84
+ } from './ReactProfilerTimer' ;
85
+ import { ProfileMode } from './ReactTypeOfMode' ;
79
86
import { commitUpdateQueue } from './ReactUpdateQueue' ;
80
87
import {
81
88
getPublicInstance ,
@@ -112,6 +119,7 @@ import {
112
119
markCommitTimeOfFallback ,
113
120
enqueuePendingPassiveHookEffectMount ,
114
121
enqueuePendingPassiveHookEffectUnmount ,
122
+ enqueuePendingPassiveProfilerEffect ,
115
123
} from './ReactFiberWorkLoop' ;
116
124
import {
117
125
NoEffect as NoHookEffect ,
@@ -174,7 +182,16 @@ const callComponentWillUnmountWithTimer = function(current, instance) {
174
182
startPhaseTimer ( current , 'componentWillUnmount' ) ;
175
183
instance . props = current . memoizedProps ;
176
184
instance . state = current . memoizedState ;
177
- instance . componentWillUnmount ( ) ;
185
+ if ( enableProfilerTimer && current . mode & ProfileMode ) {
186
+ try {
187
+ startLayoutEffectTimer ( ) ;
188
+ instance . componentWillUnmount ( ) ;
189
+ } finally {
190
+ recordLayoutEffectDuration ( current ) ;
191
+ }
192
+ } else {
193
+ instance . componentWillUnmount ( ) ;
194
+ }
178
195
stopPhaseTimer ( ) ;
179
196
} ;
180
197
@@ -429,8 +446,27 @@ export function commitPassiveHookEffects(finishedWork: Fiber): void {
429
446
// TODO (#17945) We should call all passive destroy functions (for all fibers)
430
447
// before calling any create functions. The current approach only serializes
431
448
// these for a single fiber.
432
- commitHookEffectListUnmount ( HookPassive | HookHasEffect , finishedWork ) ;
433
- commitHookEffectListMount ( HookPassive | HookHasEffect , finishedWork ) ;
449
+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
450
+ try {
451
+ startPassiveEffectTimer ( ) ;
452
+ commitHookEffectListUnmount (
453
+ HookPassive | HookHasEffect ,
454
+ finishedWork ,
455
+ ) ;
456
+ commitHookEffectListMount (
457
+ HookPassive | HookHasEffect ,
458
+ finishedWork ,
459
+ ) ;
460
+ } finally {
461
+ recordPassiveEffectDuration ( finishedWork ) ;
462
+ }
463
+ } else {
464
+ commitHookEffectListUnmount (
465
+ HookPassive | HookHasEffect ,
466
+ finishedWork ,
467
+ ) ;
468
+ commitHookEffectListMount ( HookPassive | HookHasEffect , finishedWork ) ;
469
+ }
434
470
break ;
435
471
}
436
472
default :
@@ -439,6 +475,61 @@ export function commitPassiveHookEffects(finishedWork: Fiber): void {
439
475
}
440
476
}
441
477
478
+ export function commitPassiveEffectDurations (
479
+ finishedRoot : FiberRoot ,
480
+ finishedWork : Fiber ,
481
+ ) : void {
482
+ if ( enableProfilerTimer ) {
483
+ // Only Profilers with work in their subtree will have an Update effect scheduled.
484
+ if ( ( finishedWork . effectTag & Update ) !== NoEffect ) {
485
+ switch ( finishedWork . tag ) {
486
+ case Profiler : {
487
+ const { passiveEffectDuration} = finishedWork . stateNode ;
488
+ const { id, onPostCommit} = finishedWork . memoizedProps ;
489
+
490
+ // This value will still reflect the previous commit phase.
491
+ // It does not get reset until the start of the next commit phase.
492
+ const commitTime = getCommitTime ( ) ;
493
+
494
+ if ( typeof onPostCommit === 'function' ) {
495
+ if ( enableSchedulerTracing ) {
496
+ onPostCommit (
497
+ id ,
498
+ finishedWork . alternate === null ? 'mount' : 'update' ,
499
+ passiveEffectDuration ,
500
+ commitTime ,
501
+ finishedRoot . memoizedInteractions ,
502
+ ) ;
503
+ } else {
504
+ onPostCommit (
505
+ id ,
506
+ finishedWork . alternate === null ? 'mount' : 'update' ,
507
+ passiveEffectDuration ,
508
+ commitTime ,
509
+ ) ;
510
+ }
511
+ }
512
+
513
+ // Bubble times to the next nearest ancestor Profiler.
514
+ // After we process that Profiler, we'll bubble further up.
515
+ let parentFiber = finishedWork . return ;
516
+ while ( parentFiber !== null ) {
517
+ if ( parentFiber . tag === Profiler ) {
518
+ const parentStateNode = parentFiber . stateNode ;
519
+ parentStateNode . passiveEffectDuration += passiveEffectDuration ;
520
+ break ;
521
+ }
522
+ parentFiber = parentFiber . return ;
523
+ }
524
+ break ;
525
+ }
526
+ default :
527
+ break ;
528
+ }
529
+ }
530
+ }
531
+ }
532
+
442
533
function commitLifeCycles (
443
534
finishedRoot : FiberRoot ,
444
535
current : Fiber | null ,
@@ -454,7 +545,16 @@ function commitLifeCycles(
454
545
// This is done to prevent sibling component effects from interfering with each other,
455
546
// e.g. a destroy function in one component should never override a ref set
456
547
// by a create function in another component during the same commit.
457
- commitHookEffectListMount ( HookLayout | HookHasEffect , finishedWork ) ;
548
+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
549
+ try {
550
+ startLayoutEffectTimer ( ) ;
551
+ commitHookEffectListMount ( HookLayout | HookHasEffect , finishedWork ) ;
552
+ } finally {
553
+ recordLayoutEffectDuration ( finishedWork ) ;
554
+ }
555
+ } else {
556
+ commitHookEffectListMount ( HookLayout | HookHasEffect , finishedWork ) ;
557
+ }
458
558
459
559
if ( deferPassiveEffectCleanupDuringUnmount ) {
460
560
schedulePassiveEffects ( finishedWork ) ;
@@ -496,7 +596,16 @@ function commitLifeCycles(
496
596
}
497
597
}
498
598
}
499
- instance . componentDidMount ( ) ;
599
+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
600
+ try {
601
+ startLayoutEffectTimer ( ) ;
602
+ instance . componentDidMount ( ) ;
603
+ } finally {
604
+ recordLayoutEffectDuration ( finishedWork ) ;
605
+ }
606
+ } else {
607
+ instance . componentDidMount ( ) ;
608
+ }
500
609
stopPhaseTimer ( ) ;
501
610
} else {
502
611
const prevProps =
@@ -535,11 +644,24 @@ function commitLifeCycles(
535
644
}
536
645
}
537
646
}
538
- instance . componentDidUpdate (
539
- prevProps ,
540
- prevState ,
541
- instance . __reactInternalSnapshotBeforeUpdate ,
542
- ) ;
647
+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
648
+ try {
649
+ startLayoutEffectTimer ( ) ;
650
+ instance . componentDidUpdate (
651
+ prevProps ,
652
+ prevState ,
653
+ instance . __reactInternalSnapshotBeforeUpdate ,
654
+ ) ;
655
+ } finally {
656
+ recordLayoutEffectDuration ( finishedWork ) ;
657
+ }
658
+ } else {
659
+ instance . componentDidUpdate (
660
+ prevProps ,
661
+ prevState ,
662
+ instance . __reactInternalSnapshotBeforeUpdate ,
663
+ ) ;
664
+ }
543
665
stopPhaseTimer ( ) ;
544
666
}
545
667
}
@@ -632,7 +754,10 @@ function commitLifeCycles(
632
754
}
633
755
case Profiler : {
634
756
if ( enableProfilerTimer ) {
635
- const onRender = finishedWork . memoizedProps . onRender ;
757
+ const { onCommit, onRender} = finishedWork . memoizedProps ;
758
+ const { effectDuration} = finishedWork . stateNode ;
759
+
760
+ const commitTime = getCommitTime ( ) ;
636
761
637
762
if ( typeof onRender === 'function' ) {
638
763
if ( enableSchedulerTracing ) {
@@ -642,7 +767,7 @@ function commitLifeCycles(
642
767
finishedWork . actualDuration ,
643
768
finishedWork . treeBaseDuration ,
644
769
finishedWork . actualStartTime ,
645
- getCommitTime ( ) ,
770
+ commitTime ,
646
771
finishedRoot . memoizedInteractions ,
647
772
) ;
648
773
} else {
@@ -652,10 +777,46 @@ function commitLifeCycles(
652
777
finishedWork . actualDuration ,
653
778
finishedWork . treeBaseDuration ,
654
779
finishedWork . actualStartTime ,
655
- getCommitTime ( ) ,
780
+ commitTime ,
656
781
) ;
657
782
}
658
783
}
784
+
785
+ if ( typeof onCommit === 'function' ) {
786
+ if ( enableSchedulerTracing ) {
787
+ onCommit (
788
+ finishedWork . memoizedProps . id ,
789
+ current === null ? 'mount' : 'update' ,
790
+ effectDuration ,
791
+ commitTime ,
792
+ finishedRoot . memoizedInteractions ,
793
+ ) ;
794
+ } else {
795
+ onCommit (
796
+ finishedWork . memoizedProps . id ,
797
+ current === null ? 'mount' : 'update' ,
798
+ effectDuration ,
799
+ commitTime ,
800
+ ) ;
801
+ }
802
+ }
803
+
804
+ // Schedule a passive effect for this Profiler to call onPostCommit hooks.
805
+ // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,
806
+ // because the effect is also where times bubble to parent Profilers.
807
+ enqueuePendingPassiveProfilerEffect ( finishedWork ) ;
808
+
809
+ // Propagate layout effect durations to the next nearest Profiler ancestor.
810
+ // Do not reset these values until the next render so DevTools has a chance to read them first.
811
+ let parentFiber = finishedWork . return ;
812
+ while ( parentFiber !== null ) {
813
+ if ( parentFiber . tag === Profiler ) {
814
+ const parentStateNode = parentFiber . stateNode ;
815
+ parentStateNode . effectDuration += effectDuration ;
816
+ break ;
817
+ }
818
+ parentFiber = parentFiber . return ;
819
+ }
659
820
}
660
821
return ;
661
822
}
@@ -803,7 +964,13 @@ function commitUnmount(
803
964
if ( ( tag & HookPassive ) !== NoHookEffect ) {
804
965
enqueuePendingPassiveHookEffectUnmount ( current , effect ) ;
805
966
} else {
806
- safelyCallDestroy ( current , destroy ) ;
967
+ if ( enableProfilerTimer && current . mode & ProfileMode ) {
968
+ startLayoutEffectTimer ( ) ;
969
+ safelyCallDestroy ( current , destroy ) ;
970
+ recordLayoutEffectDuration ( current ) ;
971
+ } else {
972
+ safelyCallDestroy ( current , destroy ) ;
973
+ }
807
974
}
808
975
}
809
976
effect = effect . next ;
@@ -828,9 +995,19 @@ function commitUnmount(
828
995
runWithPriority ( priorityLevel , ( ) => {
829
996
let effect = firstEffect ;
830
997
do {
831
- const destroy = effect . destroy ;
998
+ const { destroy, tag } = effect ;
832
999
if ( destroy !== undefined ) {
833
- safelyCallDestroy ( current , destroy ) ;
1000
+ if ( enableProfilerTimer && current . mode & ProfileMode ) {
1001
+ if ( ( tag & HookPassive ) !== NoHookEffect ) {
1002
+ safelyCallDestroy ( current , destroy ) ;
1003
+ } else {
1004
+ startLayoutEffectTimer ( ) ;
1005
+ safelyCallDestroy ( current , destroy ) ;
1006
+ recordLayoutEffectDuration ( current ) ;
1007
+ }
1008
+ } else {
1009
+ safelyCallDestroy ( current , destroy ) ;
1010
+ }
834
1011
}
835
1012
effect = effect . next ;
836
1013
} while ( effect !== firstEffect ) ;
@@ -1372,7 +1549,19 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1372
1549
// This prevents sibling component effects from interfering with each other,
1373
1550
// e.g. a destroy function in one component should never override a ref set
1374
1551
// by a create function in another component during the same commit.
1375
- commitHookEffectListUnmount ( HookLayout | HookHasEffect , finishedWork ) ;
1552
+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
1553
+ try {
1554
+ startLayoutEffectTimer ( ) ;
1555
+ commitHookEffectListUnmount (
1556
+ HookLayout | HookHasEffect ,
1557
+ finishedWork ,
1558
+ ) ;
1559
+ } finally {
1560
+ recordLayoutEffectDuration ( finishedWork ) ;
1561
+ }
1562
+ } else {
1563
+ commitHookEffectListUnmount ( HookLayout | HookHasEffect , finishedWork ) ;
1564
+ }
1376
1565
return ;
1377
1566
}
1378
1567
case Profiler : {
@@ -1415,7 +1604,16 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1415
1604
// This prevents sibling component effects from interfering with each other,
1416
1605
// e.g. a destroy function in one component should never override a ref set
1417
1606
// by a create function in another component during the same commit.
1418
- commitHookEffectListUnmount ( HookLayout | HookHasEffect , finishedWork ) ;
1607
+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
1608
+ try {
1609
+ startLayoutEffectTimer ( ) ;
1610
+ commitHookEffectListUnmount ( HookLayout | HookHasEffect , finishedWork ) ;
1611
+ } finally {
1612
+ recordLayoutEffectDuration ( finishedWork ) ;
1613
+ }
1614
+ } else {
1615
+ commitHookEffectListUnmount ( HookLayout | HookHasEffect , finishedWork ) ;
1616
+ }
1419
1617
return ;
1420
1618
}
1421
1619
case ClassComponent : {
0 commit comments