@@ -13,8 +13,16 @@ const SUSPENSE_PENDING_START_DATA = '$?';
13
13
const SUSPENSE_QUEUED_START_DATA = '$~' ;
14
14
const SUSPENSE_FALLBACK_START_DATA = '$!' ;
15
15
16
+ const FALLBACK_THROTTLE_MS = 300 ;
17
+
16
18
const SUSPENSEY_FONT_AND_IMAGE_TIMEOUT = 500 ;
17
19
20
+ // If you have a target goal in mind for a metric to hit, you don't want the
21
+ // only reason you miss it by a little bit to be throttling heuristics.
22
+ // This tries to avoid throttling if avoiding it would let you hit this metric.
23
+ // This is derived from trying to hit an LCP of 2.5 seconds with some head room.
24
+ const TARGET_VANITY_METRIC = 2300 ;
25
+
18
26
// TODO: Symbols that are referenced outside this module use dynamic accessor
19
27
// notation instead of dot notation to prevent Closure's advanced compilation
20
28
// mode from renaming. We could use extern files instead, but I couldn't get it
@@ -290,9 +298,18 @@ export function revealCompletedBoundariesWithViewTransitions(
290
298
}
291
299
return Promise . race ( [
292
300
Promise . all ( blockingPromises ) ,
293
- new Promise ( resolve =>
294
- setTimeout ( resolve , SUSPENSEY_FONT_AND_IMAGE_TIMEOUT ) ,
295
- ) ,
301
+ new Promise ( resolve => {
302
+ const currentTime = performance . now ( ) ;
303
+ const msUntilTimeout =
304
+ // If the throttle would make us miss the target metric, then shorten the throttle.
305
+ // performance.now()'s zero value is assumed to be the start time of the metric.
306
+ currentTime < TARGET_VANITY_METRIC &&
307
+ currentTime > TARGET_VANITY_METRIC - FALLBACK_THROTTLE_MS
308
+ ? TARGET_VANITY_METRIC - currentTime
309
+ : // Otherwise it's throttled starting from last commit time.
310
+ SUSPENSEY_FONT_AND_IMAGE_TIMEOUT ;
311
+ setTimeout ( resolve , msUntilTimeout ) ;
312
+ } ) ,
296
313
] ) ;
297
314
} ,
298
315
types : [ ] , // TODO: Add a hard coded type for Suspense reveals.
@@ -360,8 +377,6 @@ export function clientRenderBoundary(
360
377
}
361
378
}
362
379
363
- const FALLBACK_THROTTLE_MS = 300 ;
364
-
365
380
export function completeBoundary ( suspenseBoundaryID , contentID ) {
366
381
const contentNodeOuter = document . getElementById ( contentID ) ;
367
382
if ( ! contentNodeOuter ) {
@@ -395,8 +410,15 @@ export function completeBoundary(suspenseBoundaryID, contentID) {
395
410
// to flush the batch. This is delayed by the throttle heuristic.
396
411
const globalMostRecentFallbackTime =
397
412
typeof window [ '$RT' ] !== 'number' ? 0 : window [ '$RT' ] ;
413
+ const currentTime = performance . now ( ) ;
398
414
const msUntilTimeout =
399
- globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - performance . now ( ) ;
415
+ // If the throttle would make us miss the target metric, then shorten the throttle.
416
+ // performance.now()'s zero value is assumed to be the start time of the metric.
417
+ currentTime < TARGET_VANITY_METRIC &&
418
+ currentTime > TARGET_VANITY_METRIC - FALLBACK_THROTTLE_MS
419
+ ? TARGET_VANITY_METRIC - currentTime
420
+ : // Otherwise it's throttled starting from last commit time.
421
+ globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - currentTime ;
400
422
// We always schedule the flush in a timer even if it's very low or negative to allow
401
423
// for multiple completeBoundary calls that are already queued to have a chance to
402
424
// make the batch.
0 commit comments