Skip to content

Instantly share code, notes, and snippets.

@jabney
Created May 9, 2022 14:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jabney/4982a1d622eb99645f239adc55483721 to your computer and use it in GitHub Desktop.
Save jabney/4982a1d622eb99645f239adc55483721 to your computer and use it in GitHub Desktop.
An example of class composition with a timed value cache
interface IValueCache<T> {
get: () => T;
invalidate: () => void;
}
/**
* A simple cache that invalidates based on a timer. Every access of
* the value will refresh the timer.
*
* Even this simple class can be broken up into useful pieces and then
* composited into a new timer cache.
*/
class SimpleTimerCache<T> implements IValueCache<T> {
private value: T | null = null;
private timer = -1;
constructor(private readonly ms: number, private readonly cacheFn: () => T) {}
invalidate = () => void (this.value = null);
get = () => {
if (this.value == null) this.value = this.cacheFn();
if (this.ms >= 0) {
clearTimeout(this.timer);
this.timer = setTimeout(this.invalidate, this.ms);
}
return this.value;
};
}
/**
* Basic cache will store a value until it's invalidated.
*/
class BasicCache<T> implements IValueCache<T> {
private value: T | null = null;
constructor(private readonly refresh: () => T) {}
invalidate = () => void (this.value = null);
get = () => {
if (this.value == null) {
this.value = this.refresh();
}
return this.value;
};
}
/**
* Basic timer can be started, stopped, and reset.
*/
class BasicTimer {
private id = -1;
constructor(private readonly ms: number, private readonly action: () => void) {}
start = () => void (this.id = setTimeout(this.action, this.ms));
stop = () => void clearTimeout(this.id);
reset = () => void (this.stop(), this.start());
}
/**
* This timer cache is a composite of the basic cache and the basic timer.
*/
class TimerCache<T> implements IValueCache<T> {
private cache: BasicCache<T>;
private timer: BasicTimer;
constructor(ms: number, refresh: () => T) {
this.cache = new BasicCache<T>(refresh);
this.timer = new BasicTimer(ms, this.cache.invalidate);
}
get = () => {
this.timer.reset();
return this.cache.get();
};
invalidate = () => this.cache.invalidate();
}
(() => {
const cache = new TimerCache(1000, () => (console.log("cache refreshed"), 1));
cache.get();
setTimeout(cache.get, 500);
setTimeout(cache.get, 1000);
setTimeout(cache.get, 1500);
setTimeout(cache.get, 2000);
setTimeout(cache.get, 2500);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment