We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Caching

It's time to implement caching! This will make moving around the map feel a lot snappier. We'll be building a flexible caching system to help with performance in future steps.

What Is a Cache?

A cache temporarily stores data so that future requests for that data can be served faster.

In our case, we'll be caching responses from the PokeAPI so that when we need that same data again, we can grab it from memory instead of making another network request.

Assignment

    • createdAt - A [number] for the Date.now() value that represents when the entry was created.
    • val - A T generic that represents the object we're caching.
export class Cache {
  #cache = new Map<string, CacheEntry<any>>();
}

Great, now we can add and retrieve entries from our cache... but we don't want it to just grow forever! Let's add a loop that cleans up old entries.

export class Cache {
  #cache = new Map<string, CacheEntry<any>>();
  #reapIntervalId: NodeJS.Timeout | undefined = undefined;
  #interval: number;
}

Run and submit the CLI tests from the root of the repo.

Tip

This example code should give you an idea of how to get started testing your cache, but feel free to add a few more cases.

import { Cache } from "./pokecache.js";
import { test, expect } from "vitest";

test.concurrent.each([
  {
    key: "https://example.com",
    val: "testdata",
    interval: 500, // 1/2 second
  },
  {
    key: "https://example.com/path",
    val: "moretestdata",
    interval: 1000, // 1 second
  },
])("Test Caching $interval ms", async ({ key, val, interval }) => {
  const cache = new Cache(interval);

  cache.add(key, val);
  const cached = cache.get(key);
  expect(cached).toBe(val);

  await new Promise((resolve) => setTimeout(resolve, interval * 2));
  const reaped = cache.get(key);
  expect(reaped).toBe(undefined);

  cache.stopReapLoop();
});