@@ -143,6 +143,7 @@ import ReactDOMSharedInternals from 'shared/ReactDOMSharedInternals';
143143export { default as rendererVersion } from 'shared/ReactVersion' ;
144144
145145import noop from 'shared/noop' ;
146+ import estimateBandwidth from './estimateBandwidth' ;
146147
147148export const rendererPackageName = 'react-dom' ;
148149export const extraDevToolsConfig = null ;
@@ -5907,6 +5908,7 @@ type SuspendedState = {
59075908 stylesheets : null | Map < StylesheetResource , HoistableRoot > ,
59085909 count : number , // suspensey css and active view transitions
59095910 imgCount : number , // suspensey images
5911+ imgBytes : number , // number of bytes we estimate needing to download
59105912 waitingForImages : boolean , // false when we're no longer blocking on images
59115913 unsuspend : null | ( ( ) => void ) ,
59125914} ;
@@ -5917,6 +5919,7 @@ export function startSuspendingCommit(): void {
59175919 stylesheets : null ,
59185920 count : 0 ,
59195921 imgCount : 0 ,
5922+ imgBytes : 0 ,
59205923 waitingForImages : true ,
59215924 // We use a noop function when we begin suspending because if possible we want the
59225925 // waitfor step to finish synchronously. If it doesn't we'll return a function to
@@ -5926,10 +5929,6 @@ export function startSuspendingCommit(): void {
59265929 } ;
59275930}
59285931
5929- const SUSPENSEY_STYLESHEET_TIMEOUT = 60000 ;
5930-
5931- const SUSPENSEY_IMAGE_TIMEOUT = 500 ;
5932-
59335932export function suspendInstance (
59345933 instance : Instance ,
59355934 type : Type ,
@@ -5953,6 +5952,18 @@ export function suspendInstance(
59535952 // The loading should have already started at this point, so it should be enough to
59545953 // just call decode() which should also wait for the data to finish loading.
59555954 state . imgCount ++ ;
5955+ // Estimate the byte size that we're about to download based on the width/height
5956+ // specified in the props. This is best practice to know ahead of time but if it's
5957+ // unspecified we'll fallback to a guess of 100x100 pixels.
5958+ if ( ! ( instance : any ) . complete ) {
5959+ const width : number = ( instance : any ) . width || 100 ;
5960+ const height : number = ( instance : any ) . height || 100 ;
5961+ const pixelRatio : number =
5962+ typeof devicePixelRatio === 'number' ? devicePixelRatio : 1 ;
5963+ const pixelsToDownload = width * height * pixelRatio ;
5964+ const AVERAGE_BYTE_PER_PIXEL = 0.25 ;
5965+ state . imgBytes += pixelsToDownload * AVERAGE_BYTE_PER_PIXEL ;
5966+ }
59565967 const ping = onUnsuspendImg . bind ( state ) ;
59575968 // $FlowFixMe[prop-missing]
59585969 instance . decode ( ) . then ( ping , ping ) ;
@@ -6070,6 +6081,14 @@ export function suspendOnActiveViewTransition(rootContainer: Container): void {
60706081 activeViewTransition . finished . then ( ping , ping ) ;
60716082}
60726083
6084+ const SUSPENSEY_STYLESHEET_TIMEOUT = 60000 ;
6085+
6086+ const SUSPENSEY_IMAGE_TIMEOUT = 800 ;
6087+
6088+ const SUSPENSEY_IMAGE_TIME_ESTIMATE = 500 ;
6089+
6090+ let estimatedBytesWithinLimit : number = 0 ;
6091+
60736092export function waitForCommitToBeReady (
60746093 timeoutOffset : number ,
60756094) : null | ( ( ( ) => void ) => ( ) => void ) {
@@ -6109,6 +6128,18 @@ export function waitForCommitToBeReady(
61096128 }
61106129 } , SUSPENSEY_STYLESHEET_TIMEOUT + timeoutOffset ) ;
61116130
6131+ if ( state . imgBytes > 0 && estimatedBytesWithinLimit === 0 ) {
6132+ // Estimate how many bytes we can download in 500ms.
6133+ const mbps = estimateBandwidth ( ) ;
6134+ estimatedBytesWithinLimit = mbps * 125 * SUSPENSEY_IMAGE_TIME_ESTIMATE ;
6135+ }
6136+ // If we have more images to download than we expect to fit in the timeout, then
6137+ // don't wait for images longer than 50ms. The 50ms lets us still do decoding and
6138+ // hitting caches if it turns out that they're already in the HTTP cache.
6139+ const imgTimeout =
6140+ state . imgBytes > estimatedBytesWithinLimit
6141+ ? 50
6142+ : SUSPENSEY_IMAGE_TIMEOUT ;
61126143 const imgTimer = setTimeout ( ( ) => {
61136144 // We're no longer blocked on images. If CSS resolves after this we can commit.
61146145 state . waitingForImages = false ;
@@ -6122,7 +6153,7 @@ export function waitForCommitToBeReady(
61226153 unsuspend ( ) ;
61236154 }
61246155 }
6125- } , SUSPENSEY_IMAGE_TIMEOUT + timeoutOffset ) ;
6156+ } , imgTimeout + timeoutOffset ) ;
61266157
61276158 state . unsuspend = commit ;
61286159
0 commit comments