1+ // Inspired by the prefetching logic in Gatsby.js
2+
13const support = function ( feature ) {
24 if ( typeof document === `undefined` ) {
35 return false ;
@@ -11,23 +13,66 @@ const support = function (feature) {
1113 return false ;
1214 }
1315} ;
16+
1417const linkPrefetchStrategy = function ( url ) {
15- if ( typeof document === `undefined` ) {
16- return ;
17- }
18- const link = document . createElement ( `link` ) ;
19- link . setAttribute ( `rel` , `prefetch` ) ;
20- link . setAttribute ( `href` , url ) ;
21- const parentElement =
22- document . getElementsByTagName ( `head` ) [ 0 ] ||
23- document . getElementsByName ( `script` ) [ 0 ] . parentNode ;
24- parentElement . appendChild ( link ) ;
18+ return new Promise ( ( resolve , reject ) => {
19+ if ( typeof document === `undefined` ) {
20+ reject ( ) ;
21+ return ;
22+ }
23+
24+ const link = document . createElement ( `link` ) ;
25+ link . setAttribute ( `rel` , `prefetch` ) ;
26+ link . setAttribute ( `href` , url ) ;
27+
28+ link . onload = resolve ;
29+ link . onerror = reject ;
30+
31+ const parentElement =
32+ document . getElementsByTagName ( `head` ) [ 0 ] ||
33+ document . getElementsByName ( `script` ) [ 0 ] . parentNode ;
34+ parentElement . appendChild ( link ) ;
35+ } ) ;
2536} ;
37+
2638const xhrPrefetchStrategy = function ( url ) {
27- const req = new XMLHttpRequest ( ) ;
28- req . open ( `GET` , url , true ) ;
29- req . withCredentials = true ;
30- req . send ( null ) ;
39+ return new Promise ( ( resolve , reject ) => {
40+ const req = new XMLHttpRequest ( ) ;
41+ req . open ( `GET` , url , true ) ;
42+ req . withCredentials = true ;
43+
44+ req . onload = ( ) => {
45+ if ( req . status === 200 ) {
46+ resolve ( ) ;
47+ } else {
48+ reject ( ) ;
49+ }
50+ } ;
51+
52+ req . send ( null ) ;
53+ } ) ;
54+ } ;
55+
56+ const highPriFetchStrategy = function ( url ) {
57+ return new Promise ( ( resolve , reject ) => {
58+ // TODO: Investigate using preload for high-priority
59+ // fetches. May have to sniff file-extension to provide
60+ // valid 'as' values. In the future, we may be able to
61+ // use Priority Hints here.
62+ if ( self . fetch === undefined ) {
63+ xhrPrefetchStrategy ( url )
64+ . then ( ( ) => {
65+ resolve ( ) ;
66+ } ) ;
67+ } else {
68+ // As of 2018, fetch() is high-priority in Chrome
69+ // and medium-priority in Safari.
70+ fetch ( url , { credentials : `include` } )
71+ . then ( ( ) => {
72+ resolve ( ) ;
73+ } ) ;
74+ }
75+ } ) ;
3176} ;
3277
3378const supportedPrefetchStrategy = support ( `prefetch` )
@@ -36,22 +81,35 @@ const supportedPrefetchStrategy = support(`prefetch`)
3681
3782const preFetched = { } ;
3883
39- const prefetch = function ( url ) {
40- if ( preFetched [ url ] ) {
41- return ;
42- }
43- preFetched [ url ] = true ;
44- supportedPrefetchStrategy ( url ) ;
84+ const prefetch = function ( url , priority ) {
85+ return new Promise ( resolve => {
86+ if ( preFetched [ url ] ) {
87+ resolve ( ) ;
88+ return ;
89+ }
90+
91+ if ( priority && priority === `high` ) {
92+ highPriFetchStrategy ( url ) ;
93+ } else {
94+ supportedPrefetchStrategy ( url )
95+ . then ( ( ) => {
96+ resolve ( ) ;
97+ preFetched [ url ] = true ;
98+ } )
99+ . catch ( ( ) => { } ) ;
100+ } ;
101+ } ) ;
45102} ;
46103
47104/**
48105 * Prefetch an array of URLs using rel=prefetch
49106 * if supported. Falls back to XHR otherwise.
50- * @param {Array } urls Array of URLs to prefetch
107+ * @param {Array } urls - Array of URLs to prefetch
108+ * @param {string } priority - "priority" of the request
51109 */
52- const prefetchLinks = function ( urls ) {
110+ const prefetchLinks = function ( urls , priority ) {
53111 urls . forEach ( url => {
54- prefetch ( url ) ;
112+ prefetch ( url , priority ) ;
55113 } ) ;
56114} ;
57115
0 commit comments