Skip to content

Instantly share code, notes, and snippets.

@dinigo
Last active December 14, 2017 23:44
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 dinigo/ebe022ae18e715e7312901bf06cbeae9 to your computer and use it in GitHub Desktop.
Save dinigo/ebe022ae18e715e7312901bf06cbeae9 to your computer and use it in GitHub Desktop.
Cache requests instead of firing them to the API

Cached Runner

Receives a period of time and a request function, and performs all async operations to get the data. If you retry the request in a time shorter than the period it returns the cached result instead.

You can also set a postprocess function and another function that runs every time.

Simple example

Usage

const simpleCahedRun = new CachedRun(2500, ()=>Math.random());
simpleCahedRun.start().then(res => console.log(res)); // run instantly
setTimeout(() => simpleCahedRun.start().then(res => console.log(res)),1000); // run after 1 second
setTimeout(() => simpleCahedRun.start().then(res => console.log(res)),3000); // run after 3 secons
setTimeout(() => simpleCahedRun.refresh(),3500); // force refresh
setTimeout(() => simpleCahedRun.start().then(res => console.log(res)),4000); // run after 4 secons```

Output

> 0.06756653717504979 // run instantly: new cache until 2.5s
> 0.06756653717504979 // run after 1 second: get from cache
> 0.04633045049386242 // run after 3 seconds: new cache until 5s
                      // force refresh
> 0.20170561495875194 // run after 4 seconds: forced refresh

Complete Example

Here we set all available options.

const period = 2000;  // ms
const allways = data => +new Date() + ' --> ' + data;  // an allways run function that adds a timestamp
const request = () => Math.random();  // a request function that generates a random number
const process = num => `~(${Math.ceil(num*100)})~`;
const cachedRun = new CachedRun(period, request, process, allways);
cachedRun.start().then(res => console.log(res));
setTimeout(() => cachedRun.start().then(res => console.log(res)),1000);
setTimeout(() => cachedRun.start().then(res => console.log(res)),3000);

Inmediate after invocation request -> process -> cached -> allways -> returned. New timestamp and new random number:

> "1513186989013 --> ~(4)~"

One second after invocation data isn't refreshed since period hasn't expired so: cached -> allways -> returned. New timestamp and cached random number:

> "1513186990016 --> ~(4)~"

Three secons after first invocation cache has expired, so request is rerun: request -> process -> cached -> allways -> returned. New timestamp and new random number:

> "1513186992017 --> ~(90)~"
class CachedRun {
/**
* Constructor for the class. Receives a period and a request function to run.
*
* @param {number} period - Number of millis to keep the cache.
* @param {function} request - Function that returns the requested value.
* @param {function} [process] - Run data from the request through this function before caching.
* @param {function} [allways] - Run data through this allways at the end of the pipeline.
*/
constructor(period, request, process, allways){
this.period = period;
this.request = request;
this.postProcess = process || (el=>el);
this.allwaysRun = allways || (el=>el);
this.lastCall = 0;
this.self = this;
}
/**
* Run the request function and the postprocess function (if there's one defined).
*
* @return {Promise} Promise with the requested values allready processed.
*/
getFreshResults(){
return Promise
.resolve(this.request())
.then(res => this.postProcess(res));
}
/**
* Stores cache and manages timer.
*
* @param {Object} [results] - Results from the request and further postprocess.
* @param {Promise} Promise with the cached results processed.
*/
cacheResults(results){
if(results) {
this.cache = results;
this.lastCall = +new Date();
}
return Promise
.resolve(this.cache)
.then(data => this.allwaysRun(data));
}
/**
* Run the pipeline according to the configuration.
*
* @return {Promise} Data run through all the pipeline.
*/
start(){
return (new Date() - this.lastCall > this.period)?
this.getFreshResults().then(res => this.cacheResults(res)) : this.cacheResults();
}
/**
* Forces the next run to refresh the cache
*/
refresh(){
this.lastCall = 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment