Last active
November 25, 2019 11:49
-
-
Save radum/5453919ae48163a8bda495fd91774d9e to your computer and use it in GitHub Desktop.
Request With Intent Caching Strategies in the age of PWAs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// KEEP A FALLBACK IMAGE IN YOUR BACK POCKET | |
// Assuming you want to use a fallback in more than one networking recipe, | |
// you can set up a named function that will respond with that resource: | |
function respondWithFallbackImage() { | |
return caches.match( "/i/fallbacks/offline.svg" ); | |
} | |
// Then, within a fetch event handler, you can use that function to provide that fallback image | |
// when requests for images fail at the network: | |
self.addEventListener( "fetch", event => { | |
const request = event.request; | |
if ( request.headers.get("Accept").includes("image") ) { | |
event.respondWith( | |
return fetch( request, { mode: 'no-cors' } ) | |
.then( response => { | |
return response; | |
}) | |
.catch( | |
respondWithFallbackImage | |
); | |
); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// THE CACHING STRATEGY: PRIORITIZE CERTAIN MEDIA | |
// If you consider your media with this division in mind, | |
// you can establish some general guidelines for handling each, based on the situation. | |
// In other words, a caching strategy. | |
/** | |
* | Media category | Fast connection | Save-Data | Slow connection | No network | | |
* |----------------|------------------------------|--------------------------|-----------------|------------| | |
* | Critical | Load media | Replace with placeholder | | | | |
* | Nice-to-have | Load media | Replace with placeholder | | | | |
* | Non-critical | Remove from content entirely | | | | | |
*/ | |
const high_priority = [ | |
/aaron\-gustafson\.com/, | |
/adaptivewebdesign\.info/ | |
]; | |
// With that high_priority variable defined, I can create a function that will let me know | |
// if a given image request (for example) is a high priority request or not: | |
function isHighPriority( url ) { | |
// how many high priority links are we dealing with? | |
let i = high_priority.length; | |
// loop through each | |
while ( i-- ) { | |
// does the request URL match this regular expression? | |
if ( high_priority[i].test( url ) ) { | |
// yes, it’s a high priority request | |
return true; | |
} | |
} | |
// no matches, not high priority | |
return false; | |
} | |
// Adding support for prioritizing media requests only requires adding a new conditional | |
// into the fetch event handler, like we did with Save-Data. | |
// Your specific recipe for network and cache handling will likely differ, | |
// but here was how I chose to mix in this logic within image requests: | |
// Check the cache first | |
// Return the cached image if we have one | |
// If the image is not in the cache, continue | |
// Is this image high priority? | |
if ( isHighPriority( url ) ) { | |
// Fetch the image | |
// If the fetch succeeds, save a copy in the cache | |
// If not, respond with an "offline" placeholder | |
// Not high priority | |
} else { | |
// Should I save data? | |
if ( save_data ) { | |
// Respond with a "saving data" placeholder | |
// Not saving data | |
} else { | |
// Fetch the image | |
// If the fetch succeeds, save a copy in the cache | |
// If not, respond with an "offline" placeholder | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// RESPECT A USER’S CHOICE TO SAVE DATA | |
// Some users reduce their data consumption by entering a “lite” mode or turning on a “data saver” feature. | |
// When this happens, browsers will often send a Save-Data header with their network requests. | |
// Within your Service Worker, you can look for this header and adjust your responses accordingly. | |
// First, you look for the header: | |
let save_data = false; | |
if ( 'connection' in navigator ) { | |
save_data = navigator.connection.saveData; | |
} | |
// Then, within your fetch handler for images, you might choose to preemptively respond with the fallback image | |
// instead of going to the network at all: | |
self.addEventListener( "fetch", event => { | |
const request = event.request; | |
if ( request.headers.get("Accept").includes("image") ) { | |
event.respondWith( | |
if ( save_data ) { | |
return respondWithFallbackImage(); | |
} | |
// code you saw previously | |
); | |
} | |
}); | |
// You could even take this a step further and tune respondWithFallbackImage() | |
// to provide alternate images based on what the original request was for. | |
// To do that you’d define several fallbacks globally in the Service Worker: | |
const fallback_avatar = "/i/fallbacks/avatar.svg", | |
fallback_image = "/i/fallbacks/image.svg"; | |
// Both of those files should then be cached during the Service Worker install event: | |
return cache.addAll( [ | |
fallback_avatar, | |
fallback_image | |
]); | |
// Finally, within respondWithFallbackImage() you could serve up the appropriate image based on the URL being fetched. | |
function respondWithFallbackImage( url ) { | |
const image = avatars.test( /webmention\.io/ ) ? fallback_avatar | |
: fallback_image; | |
return caches.match( image ); | |
} | |
// With that change, I’ll need to update the fetch handler to pass in request.url | |
// as an argument to respondWithFallbackImage(). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Request with Intent: Caching Strategies in the Age of PWAs
https://alistapart.com/article/request-with-intent-caching-strategies-in-the-age-of-pwas/