Skip to content

Commit c4fb77a

Browse files
committed
feat(index, prefetch) Add support for higher prio fetches
1 parent adf645e commit c4fb77a

3 files changed

Lines changed: 86 additions & 26 deletions

File tree

demo/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<script src="../dist/quicklink.umd.js"></script>
2121
<script>
2222
quicklink();
23+
// quicklink({ priority: 'high' });
2324
</script>
2425
<script type="module">
2526
// import quicklink from "../dist/quicklink.mjs";

src/index.mjs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ function extractInViewportLinks(el) {
5353
* @param {Object} options - Configuration options for quicklink
5454
* @param {Array} options.urls - Array of URLs to prefetch (override)
5555
* @param {Object} options.el - DOM element to prefetch in-viewport links of
56+
* @param {string} options.priority - Attempt to fetch with higher priority (low or high)
5657
*/
5758
export default function (options) {
58-
options = options || {};
59+
options = options || { priority: 'low' };
5960
requestIdleCallback(() => {
6061
if ('connection' in navigator) {
6162
// Don't prefetch if the user is on 2G..
@@ -69,12 +70,12 @@ export default function (options) {
6970
}
7071
// Prefetch an array of URLs if supplied (as an override)
7172
if (options.urls !== undefined && options.urls.length > 0) {
72-
prefetchLinks(options.urls);
73+
prefetchLinks(options.urls, options.priority);
7374
} else {
7475
// Element to extract in-viewport links for
7576
const el = options.el || document;
7677
extractInViewportLinks(el).then(urls => {
77-
prefetchLinks(urls);
78+
prefetchLinks(urls, options.priority);
7879
});
7980
}
8081
});

src/prefetch.mjs

Lines changed: 81 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Inspired by the prefetching logic in Gatsby.js
2+
13
const 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+
1417
const 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+
2638
const 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

3378
const supportedPrefetchStrategy = support(`prefetch`)
@@ -36,22 +81,35 @@ const supportedPrefetchStrategy = support(`prefetch`)
3681

3782
const 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

Comments
 (0)