@@ -33,7 +33,7 @@ const createPageDataUrl = rawPath => {
3333}
3434
3535function doFetch ( url , method = `GET` ) {
36- return new Promise ( ( resolve , reject ) => {
36+ return new Promise ( resolve => {
3737 const req = new XMLHttpRequest ( )
3838 req . open ( method , url , true )
3939 req . onreadystatechange = ( ) => {
@@ -98,6 +98,8 @@ export class BaseLoader {
9898 this . inFlightDb = new Map ( )
9999 this . staticQueryDb = { }
100100 this . pageDataDb = new Map ( )
101+ this . isPrefetchQueueRunning = false
102+ this . prefetchQueued = [ ]
101103 this . prefetchTriggered = new Set ( )
102104 this . prefetchCompleted = new Set ( )
103105 this . loadComponent = loadComponent
@@ -396,32 +398,90 @@ export class BaseLoader {
396398
397399 prefetch ( pagePath ) {
398400 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 ,
400417 }
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+ } )
401431
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 )
407437 }
408438
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 ) ,
412442 }
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+ )
413474
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
421483 }
422484 } )
423-
424- return true
425485 }
426486
427487 doPrefetch ( pagePath ) {
0 commit comments