@@ -946,6 +946,27 @@ function renderRoot(
946946 }
947947 case RootCompleted : {
948948 // The work completed. Ready to commit.
949+ if (
950+ ! isSync &&
951+ workInProgressRootLatestProcessedExpirationTime !== Sync &&
952+ workInProgressRootCanSuspendUsingConfig !== null
953+ ) {
954+ // If we have exceeded the minimum loading delay, which probably
955+ // means we have shown a spinner already, we might have to suspend
956+ // a bit longer to ensure that the spinner is shown for enough time.
957+ const msUntilTimeout = computeMsUntilSuspenseLoadingDelay (
958+ workInProgressRootLatestProcessedExpirationTime ,
959+ expirationTime ,
960+ workInProgressRootCanSuspendUsingConfig ,
961+ ) ;
962+ if ( msUntilTimeout > 10 ) {
963+ root . timeoutHandle = scheduleTimeout (
964+ commitRoot . bind ( null , root , expirationTime ) ,
965+ msUntilTimeout ,
966+ ) ;
967+ return null ;
968+ }
969+ }
949970 return commitRoot . bind ( null , root , expirationTime ) ;
950971 }
951972 default : {
@@ -1909,6 +1930,39 @@ function jnd(timeElapsed: number) {
19091930 : ceil ( timeElapsed / 1960 ) * 1960 ;
19101931}
19111932
1933+ function computeMsUntilSuspenseLoadingDelay (
1934+ mostRecentEventTime : ExpirationTime ,
1935+ committedExpirationTime : ExpirationTime ,
1936+ suspenseConfig : SuspenseConfig ,
1937+ ) {
1938+ if ( disableYielding ) {
1939+ // Timeout immediately when yielding is disabled.
1940+ return 0 ;
1941+ }
1942+
1943+ const minLoadingDurationMs = ( suspenseConfig . minLoadingDurationMs : any ) | 0 ;
1944+ if ( minLoadingDurationMs <= 0 ) {
1945+ return 0 ;
1946+ }
1947+ const loadingDelayMs = ( suspenseConfig . loadingDelayMs : any ) | 0 ;
1948+
1949+ // Compute the time until this render pass would expire.
1950+ const currentTimeMs : number = now ( ) ;
1951+ const eventTimeMs : number = inferTimeFromExpirationTime (
1952+ mostRecentEventTime ,
1953+ suspenseConfig ,
1954+ ) ;
1955+ const timeElapsed = currentTimeMs - eventTimeMs ;
1956+ if ( timeElapsed <= loadingDelayMs ) {
1957+ // If we haven't yet waited longer than the initial delay, we don't
1958+ // have to wait any additional time.
1959+ return 0 ;
1960+ }
1961+ const msUntilTimeout = timeElapsed - loadingDelayMs - minLoadingDurationMs ;
1962+ // This is the value that is passed to `setTimeout`.
1963+ return msUntilTimeout ;
1964+ }
1965+
19121966function computeMsUntilTimeout (
19131967 mostRecentEventTime : ExpirationTime ,
19141968 committedExpirationTime : ExpirationTime ,
0 commit comments