@@ -33,7 +33,7 @@ const createPageDataUrl = rawPath => {
33
33
}
34
34
35
35
function doFetch ( url , method = `GET` ) {
36
- return new Promise ( ( resolve , reject ) => {
36
+ return new Promise ( resolve => {
37
37
const req = new XMLHttpRequest ( )
38
38
req . open ( method , url , true )
39
39
req . onreadystatechange = ( ) => {
@@ -98,6 +98,8 @@ export class BaseLoader {
98
98
this . inFlightDb = new Map ( )
99
99
this . staticQueryDb = { }
100
100
this . pageDataDb = new Map ( )
101
+ this . isPrefetchQueueRunning = false
102
+ this . prefetchQueued = [ ]
101
103
this . prefetchTriggered = new Set ( )
102
104
this . prefetchCompleted = new Set ( )
103
105
this . loadComponent = loadComponent
@@ -396,32 +398,90 @@ export class BaseLoader {
396
398
397
399
prefetch ( pagePath ) {
398
400
if ( ! this . shouldPrefetch ( pagePath ) ) {
399
- return false
401
+ return {
402
+ then : resolve => resolve ( false ) ,
403
+ abort : ( ) => { } ,
404
+ }
405
+ }
406
+ if ( this . prefetchTriggered . has ( pagePath ) ) {
407
+ return {
408
+ then : resolve => resolve ( true ) ,
409
+ abort : ( ) => { } ,
410
+ }
411
+ }
412
+
413
+ const defer = {
414
+ resolve : null ,
415
+ reject : null ,
416
+ promise : null ,
400
417
}
418
+ defer . promise = new Promise ( ( resolve , reject ) => {
419
+ defer . resolve = resolve
420
+ defer . reject = reject
421
+ } )
422
+ this . prefetchQueued . push ( [ pagePath , defer ] )
423
+ const abortC = new AbortController ( )
424
+ abortC . signal . addEventListener ( `abort` , ( ) => {
425
+ const index = this . prefetchQueued . findIndex ( ( [ p ] ) => p === pagePath )
426
+ // remove from the queue
427
+ if ( index !== - 1 ) {
428
+ this . prefetchQueued . splice ( index , 1 )
429
+ }
430
+ } )
401
431
402
- // Tell plugins with custom prefetching logic that they should start
403
- // prefetching this path.
404
- if ( ! this . prefetchTriggered . has ( pagePath ) ) {
405
- this . apiRunner ( `onPrefetchPathname` , { pathname : pagePath } )
406
- this . prefetchTriggered . add ( pagePath )
432
+ if ( ! this . isPrefetchQueueRunning ) {
433
+ this . isPrefetchQueueRunning = true
434
+ setTimeout ( ( ) => {
435
+ this . _processNextPrefetchBatch ( )
436
+ } , 3000 )
407
437
}
408
438
409
- // If a plugin has disabled core prefetching, stop now.
410
- if ( this . prefetchDisabled ) {
411
- return false
439
+ return {
440
+ then : ( resolve , reject ) => defer . promise . then ( resolve , reject ) ,
441
+ abort : abortC . abort . bind ( abortC ) ,
412
442
}
443
+ }
444
+
445
+ _processNextPrefetchBatch ( ) {
446
+ const idleCallback = window . requestIdleCallback || ( cb => setTimeout ( cb , 0 ) )
447
+
448
+ idleCallback ( ( ) => {
449
+ const toPrefetch = this . prefetchQueued . splice ( 0 , 4 )
450
+ const prefetches = Promise . all (
451
+ toPrefetch . map ( ( [ pagePath , dPromise ] ) => {
452
+ // Tell plugins with custom prefetching logic that they should start
453
+ // prefetching this path.
454
+ if ( ! this . prefetchTriggered . has ( pagePath ) ) {
455
+ this . apiRunner ( `onPrefetchPathname` , { pathname : pagePath } )
456
+ this . prefetchTriggered . add ( pagePath )
457
+ }
458
+
459
+ // If a plugin has disabled core prefetching, stop now.
460
+ if ( this . prefetchDisabled ) {
461
+ return dPromise . resolve ( false )
462
+ }
463
+
464
+ return this . doPrefetch ( findPath ( pagePath ) ) . then ( ( ) => {
465
+ if ( ! this . prefetchCompleted . has ( pagePath ) ) {
466
+ this . apiRunner ( `onPostPrefetchPathname` , { pathname : pagePath } )
467
+ this . prefetchCompleted . add ( pagePath )
468
+ }
469
+
470
+ dPromise . resolve ( true )
471
+ } )
472
+ } )
473
+ )
413
474
414
- const realPath = findPath ( pagePath )
415
- // Todo make doPrefetch logic cacheable
416
- // eslint-disable-next-line consistent-return
417
- this . doPrefetch ( realPath ) . then ( ( ) => {
418
- if ( ! this . prefetchCompleted . has ( pagePath ) ) {
419
- this . apiRunner ( `onPostPrefetchPathname` , { pathname : pagePath } )
420
- this . prefetchCompleted . add ( pagePath )
475
+ if ( this . prefetchQueued . length ) {
476
+ prefetches . then ( ( ) => {
477
+ setTimeout ( ( ) => {
478
+ this . _processNextPrefetchBatch ( )
479
+ } , 3000 )
480
+ } )
481
+ } else {
482
+ this . isPrefetchQueueRunning = false
421
483
}
422
484
} )
423
-
424
- return true
425
485
}
426
486
427
487
doPrefetch ( pagePath ) {
0 commit comments