diff --git a/src/index.mjs b/src/index.mjs index 62d28127..bd03ba10 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -25,27 +25,23 @@ import requestIdleCallback from './request-idle-callback.mjs'; * @return {Promise} resolving with list of URLs found */ function fetchInViewportLinks(el, options) { - return new Promise((resolve, reject) => { - const urls = []; - const links = el.querySelectorAll('a'); - const observer = new IntersectionObserver(entries => { - entries.forEach(entry => { - // Link is in the view - if (entry.intersectionRatio > 0) { - urls.push(entry.target.href); - } else { - // Link is out of the view - } + const links = Array.from(el.querySelectorAll('a')); + const observer = new IntersectionObserver(entries => { + const urls = entries + .filter(entry => entry.isIntersecting) + .map(entry => { + observer.unobserve(entry.target); + return entry.target.href; }); - // prefetch() maintains a list of in-memory URLs - // previously fetched so we don't attempt a refetch - prefetchURLs(urls, options.priority); - resolve(urls); - }); - links.forEach(link => { - observer.observe(link); - }); + // prefetch() maintains a list of in-memory URLs + // previously fetched so we don't attempt a refetch + prefetchURLs(urls, options.priority); }); + links.forEach(link => { + observer.observe(link); + }); + // Return a list of found URLs + return links.map(link => link.href); }; /** @@ -54,7 +50,7 @@ function fetchInViewportLinks(el, options) { * @param {Array} urls - Array of URLs to prefetch * @param {string} priority - "priority" of the request */ -const prefetchURLs = function (urls, priority) { +function prefetchURLs(urls, priority) { urls.forEach(url => { prefetch(url, priority); }); @@ -75,24 +71,24 @@ const prefetchURLs = function (urls, priority) { * @return {Object} Promise */ export default function (options) { - return new Promise((resolve, reject) => { - options = options || { + options = { + ... { priority: 'low', timeout: 2000, - }; - const timeoutFn = options.timeoutFn || requestIdleCallback; - timeoutFn(() => { - // Prefetch an array of URLs if supplied (as an override) - if (options.urls !== undefined && options.urls.length > 0) { - prefetchURLs(options.urls, options.priority); - resolve(options.urls); - } else { - // Element to extract in-viewport links for - const el = options.el || document; - fetchInViewportLinks(el, options).then(urls => { - resolve(urls); - }); - } - }, {timeout: options.timeout}); - }); + timeoutFn: requestIdleCallback, + el: document + }, + ...options + }; + + options.timeoutFn(() => { + // Prefetch an array of URLs if supplied (as an override) + if (options.urls !== undefined && options.urls.length > 0) { + prefetchURLs(options.urls, options.priority); + return options.urls; + } else { + // Element to extract in-viewport links for + return fetchInViewportLinks(options.el, options); + } + }, {timeout: options.timeout}); } diff --git a/src/prefetch.mjs b/src/prefetch.mjs index feaedfbe..2b9ed78f 100644 --- a/src/prefetch.mjs +++ b/src/prefetch.mjs @@ -94,25 +94,17 @@ function xhrPrefetchStrategy(url) { * @return {Object} a Promise */ function highPriFetchStrategy(url) { - return new Promise((resolve, reject) => { - // TODO: Investigate using preload for high-priority - // fetches. May have to sniff file-extension to provide - // valid 'as' values. In the future, we may be able to - // use Priority Hints here. - if (self.fetch === undefined) { - xhrPrefetchStrategy(url) - .then(() => { - resolve(); - }); - } else { - // As of 2018, fetch() is high-priority in Chrome - // and medium-priority in Safari. - fetch(url, {credentials: `include`}) - .then(() => { - resolve(); - }); - } - }); + // TODO: Investigate using preload for high-priority + // fetches. May have to sniff file-extension to provide + // valid 'as' values. In the future, we may be able to + // use Priority Hints here. + if (self.fetch === undefined) { + return xhrPrefetchStrategy(url); + } else { + // As of 2018, fetch() is high-priority in Chrome + // and medium-priority in Safari. + return fetch(url, {credentials: `include`}); + } }; const supportedPrefetchStrategy = support(`prefetch`) @@ -125,40 +117,32 @@ const supportedPrefetchStrategy = support(`prefetch`) * @param {string} priority - preferred fetch priority (`low` or `high`) * @return {Object} a Promise */ -function prefetcher(url, priority) { - return new Promise(resolve => { - if ('connection' in navigator) { - // Don't prefetch if the user is on 2G.. - if (navigator.connection.effectiveType && /\slow-2g|2g/.test(navigator.connection.effectiveType)) { - resolve(); - return; - } - // Don't prefetch if Save-Data is enabled.. - if (navigator.connection.saveData) { - resolve(); - return; - } +async function prefetcher(url, priority) { + if (preFetched[url]) { + return; + } + + if ('connection' in navigator) { + // Don't prefetch if the user is on 2G.. + if ((navigator.connection.effectiveType || "").includes("2g")) { + return; } - if (preFetched[url]) { - resolve(); + // Don't prefetch if Save-Data is enabled.. + if (navigator.connection.saveData) { return; } + } + + try { if (priority && priority === `high`) { - highPriFetchStrategy(url) - .then(() => { - resolve(); - preFetched[url] = true; - }) - .catch(() => { }); + await highPriFetchStrategy(url); } else { - supportedPrefetchStrategy(url) - .then(() => { - resolve(); - preFetched[url] = true; - }) - .catch(() => { }); + await supportedPrefetchStrategy(url); }; - }); + preFetched[url] = true; + } catch(e) { + // Wanna do something? + } }; export default prefetcher;