Caching images from remote database in JS using Image constructor

Hey everyone, I’m working on a project where I need to cache images from a remote database (like AirTable) using JavaScript. The goal is to make sure users can see the images even if they lose their internet connection. I’ve tried using the Image constructor to preload about 200 images, but it’s not working as expected.

Here’s the function I’m using:

function cacheImage(imageUrl) {
  return new Promise((resolve) => {
    let cachedImg = new Image();
    cachedImg.src = imageUrl;
    cachedImg.onload = resolve;
    cachedImg.onerror = resolve;
  });
}

The problem is that when the app tries to show the images later, it ignores the cached versions and tries to load them again. This breaks the app when there’s no internet.

I’ve also tried:

  • Caching images in batches
  • Caching just one image at a time

Some images work, others don’t. The weird thing is, when I don’t cache the images and just load the page with good internet, all images show up fine. So the URLs aren’t the issue.

Any ideas on what I might be doing wrong or how to fix this? Thanks!

hey mate, have u tried using service workers for caching? they’re awesome for offline stuff. u could intercept fetch requests and serve cached images. might be worth a shot. also, check if ur browser’s cache settings aren’t messing things up. good luck!

I’ve encountered similar challenges with image caching. One approach that’s worked well for me is utilizing IndexedDB for storing image data. It offers more robust storage capabilities compared to traditional caching methods.

Here’s a basic implementation you might consider:

async function cacheImage(imageUrl) {
  const response = await fetch(imageUrl);
  const blob = await response.blob();
  const db = await openDB('ImageCache', 1, {
    upgrade(db) {
      db.createObjectStore('images');
    },
  });
  await db.put('images', blob, imageUrl);
}

async function getImage(imageUrl) {
  const db = await openDB('ImageCache', 1);
  const cachedImage = await db.get('images', imageUrl);
  return cachedImage ? URL.createObjectURL(cachedImage) : imageUrl;
}

This method provides better persistence and can handle larger datasets more efficiently. Remember to implement error handling and cache management to prevent excessive storage usage.

I’ve dealt with similar issues before, and one thing that worked for me was using the Cache API instead of relying solely on the Image constructor. It gives you more control over how images are stored and retrieved.

Here’s a basic approach you could try:

async function cacheImage(imageUrl) {
  const cache = await caches.open('image-cache');
  const response = await fetch(imageUrl);
  await cache.put(imageUrl, response);
}

async function getImage(imageUrl) {
  const cache = await caches.open('image-cache');
  const cachedResponse = await cache.match(imageUrl);
  return cachedResponse || fetch(imageUrl);
}

This way, you’re explicitly storing the image responses in the cache and can retrieve them later. When loading images in your app, use the getImage function instead of directly setting the src attribute.

Also, make sure you’re handling cases where the cache might fail or be full. You might need to implement a strategy to manage cache size and prioritize which images to keep.