Image Cache

Prefetching and the Image Cache API

Download the next screen's image while the user is still on the list. Image.prefetch(url) fills the disk cache and resolves to true; queryCache(urls) reports 'memory', 'disk' or 'disk/memory' per cached URL; and getSize(url) resolves to the pixel size. The demos serve the covers with python3 -m http.server 8000 --directory assets/covers, and adb reverse tcp:8000 tcp:8000 makes that port localhost:8000 on the emulator.

src/Prefetch.tsx: warming the cache before the screen rendersTSX
const urls = books.map((b) => coverUrl(b.id));
export function usePrefetchedCovers() {
  const [ready, setReady] = useState(false);
  useEffect(() => {
    (async () => {
      console.log('before', await Image.queryCache?.(urls.slice(0, 2)));
      const t0 = Date.now();
      const ok = await Promise.all(urls.map((url) => Image.prefetch(url)));
      console.log(`prefetched ${ok.filter(Boolean).length} in ${Date.now() - t0} ms`);
      console.log('after', await Image.queryCache?.(urls.slice(0, 2)));
      console.log('size', await Image.getSize(urls[0]));
      setReady(true);
    })().catch((e) => console.warn('prefetch failed', e));
  }, []);
  return ready;
}
Output
 LOG  before {}
 LOG  prefetched 6 in 2376 ms
 LOG  after {"http://localhost:8000/1.png": "disk", "http://localhost:8000/2.png": "disk"}
 LOG  size {"height": 600, "width": 400}

queryCache is optional in the TypeScript types, hence the ?.. After a fresh install the cache was empty ({}); the prefetch put all six covers on disk in 2.4 seconds, and getSize read the 400 x 600 pixel size without drawing anything. Prefetch only what the user will probably open next: the core Image cannot evict anything.