Skip to content

Instantly share code, notes, and snippets.

@bennadel
Last active January 26, 2022 11:03
Mixing Promises And async / await For Caching Purposes In JavaScript
figure.mouseenter( handleFigureMouseenter );
// ...
function handleFigureMouseenter() {
figure.off( "mouseenter", handleFigureMouseenter );
// Just preload a single image in each direction (Prev and Next).
preCachePrevPhoto( +prevPhoto.data( "rel" ), 1 );
preCacheNextPhoto( +nextPhoto.data( "rel" ), 1 );
}
async function preCacheNextPhoto( photoID, wiggleRoom = 3 ) {
// All recursive algorithms needs a base-case that will cause the recursion
// to halt. When we run out of wiggle room, stop recursing.
if ( wiggleRoom <= 0 ) {
return;
}
if ( ! cache[ photoID ] ) {
// CAUTION: The ApiClient returns PROMISES. Our cache is going to be
// filled with Promises, not with raw photo data.
cache[ photoID ] = apiClient.makeRequest({
url: "/index.cfm",
params: {
event: "api.sitePhotos.photo",
index: photoID
}
});
}
try {
// BLOCK AND WAIT for Promise RESOLUTION (ie, the raw photo data).
var response = await cache[ photoID ];
// Warm up the browser cache for this image binary.
new Image().src = response.src;
// Recursively cache the next photo. Note that we are NOT AWAITING this
// recursive call since we are not consuming the response. We also
// don't want any failures within the recursion to clear the cache for
// the current ID.
preCacheNextPhoto( response.nextPhotoID, --wiggleRoom );
} catch ( error ) {
// If something goes wrong, let's assume that the cached Promise is
// problematic (a rejection) and delete it. This way, the next request
// will attempt to fetch and re-cache it.
delete( cache[ photoID ] );
console.warn( "Could not pre-cache next photo." );
console.error( error );
}
}
async function showNextPhoto( photoID ) {
if ( ! cache[ photoID ] ) {
cache[ photoID ] = apiClient.makeRequest({
url: "/index.cfm",
params: {
event: "api.sitePhotos.photo",
index: photoID
}
});
}
try {
var response = await cache[ photoID ];
renderPhotoResponse( response );
// While the user is looking at the photo that we just rendered, let's
// pre-cache more photos in the background. This way, by the time the
// user goes to hit the NEXT PHOTO button, we'll (hopefully) have
// already loaded that data and can render it immediately. Note that we
// are NOT AWAITING this response since we don't care when it completes.
preCacheNextPhoto( response.nextPhotoID );
} catch ( error ) {
/// If something goes wrong, let's assume that the cached Promise is
// problematic (a rejection) and delete it. This way, the next request
// will attempt to fetch and re-cache it.
delete( cache[ photoID ] );
console.warn( "Could not show next photo information." );
console.error( error );
}
}
@stefanjudis
Copy link

@bennadel Hey Ben, I'm just reading your article including these snippets and I think you might have a typo here:

handeFigureMouseenter -> handleFigureMouseenter?

Thanks for the article!

@bennadel
Copy link
Author

Yes, good catch! I had just hand-written the code into the article (since it was heavily truncated).

@bennadel
Copy link
Author

@stefanjudis consider it fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment