@@ -946,6 +946,27 @@ function renderRoot(
946
946
}
947
947
case RootCompleted : {
948
948
// 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
+ }
949
970
return commitRoot . bind ( null , root , expirationTime ) ;
950
971
}
951
972
default : {
@@ -1909,6 +1930,39 @@ function jnd(timeElapsed: number) {
1909
1930
: ceil ( timeElapsed / 1960 ) * 1960 ;
1910
1931
}
1911
1932
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
+
1912
1966
function computeMsUntilTimeout (
1913
1967
mostRecentEventTime : ExpirationTime ,
1914
1968
committedExpirationTime : ExpirationTime ,
0 commit comments