Created
October 19, 2017 14:37
-
-
Save arpanpal010/a8221c61009951db81cb75c6ea550e40 to your computer and use it in GitHub Desktop.
A generic caching mechanism that stores in localstorage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export static class CacheService { | |
// static $inject = ["localStorageService", "$rootScope", "$timeout"] | |
private static ls : localStorageService = undefined; // wrap localstorage to hide data | |
private static instance : CacheService = undefined; | |
private callables : Object = {}; | |
private asyncCallables : Object = {}; | |
constructor(ls : any, rootScope : any, timeout : any) { | |
if(!this.instance) { | |
this.enabled = true; // toggle this to disable cache. | |
this.ls = ls; | |
this.timeout = timeout; | |
this.ls.setStorageType("sessionStorage"); | |
this.clearAtInterval(1200); // clear every 20 mins | |
// this.clearAll(); | |
if(!this.enabled) { | |
this.clearAll(); | |
} | |
this.rs = rootScope; | |
this.instance = this; | |
// window.lc = this; // for debug only | |
} | |
return this.instance; | |
} | |
create(key : string, callable : Function) { | |
const self = this; | |
self.callables[key] = callable; | |
return (refetch) => { | |
if(refetch) { | |
self.ls.remove(key); | |
} | |
if(self.isKeySet(key)) { | |
return self.getValue(key); | |
} else { | |
return self.setValue(key, callable()); | |
} | |
} | |
} | |
createAsync(key : string, callable : Function) { | |
const self = this; | |
self.asyncCallables[key] = callable; | |
return async (refetch) => { | |
if(refetch) { | |
self.ls.remove(key); | |
} | |
if(self.isKeySet(key)) { | |
return self.getValue(key); | |
} else { | |
return self.setValue(key, await callable()); | |
} | |
} | |
} | |
setValue(key : string, value : any) { | |
let now = Date.now(); | |
let old = this.getValue(key); | |
if (this.enabled) { | |
this.ls.set(key, JSON.stringify({ "timestamp": now, "value" : value })); | |
this.ls.set("CacheChangedLast", now); | |
this.rs.$broadcast("set-" + key, value, old); | |
} | |
return value; | |
} | |
updateValue(key : string, value? : any) { | |
this.setValue(key, value); | |
} | |
updateValueAsync(key : string) { | |
return async () => { | |
if(this.enabled) { | |
let v = await this.getCallable(key)(); | |
return this.setValue(key, v); | |
} | |
}; | |
} | |
getValue(key: string) { | |
//console.log(key); | |
if(this.isKeySet(key)) { | |
return JSON.parse(this.ls.get(key))["value"]; | |
} | |
return undefined; | |
} | |
getLastModified(key? : string) { | |
if(this.isKeySet(key)) { | |
return JSON.parse(this.ls.get(key))["timestamp"]; | |
} | |
return this.ls.get("CacheChangedLast") as number; | |
} | |
isKeySet(key) { | |
return this.ls.keys().filter(function(v) { | |
return v == key; | |
}).length > 0; | |
} | |
getCallable(key : string) { | |
if(typeof this.callables[key] === 'function') { | |
return this.callables[key]; | |
} | |
if(typeof this.asyncCallables[key] === 'function') { | |
return this.asyncCallables[key]; | |
} | |
return () => { | |
return undefined; | |
} | |
} | |
clearAtInterval(ts: number) { | |
let now = Date.now(); | |
// console.log( ts, now, this.getLastModified(), (ts - (now - this.getLastModified())/1000) ) | |
return this.timeout(() => { | |
this.clearAll(); | |
this.clearAtInterval(ts); | |
}, ((td : number) => { | |
let tl = Math.abs(td) > ts ? 10 : ((ts-td)>5 ? ts-td : ts)*1000; | |
//console.log("Last cache update", td , "seconds ago at", new Date(Date.now() - td)); | |
//console.log("Clear cache in", tl/1000, "seconds at", new Date(Date.now() + tl)); | |
return tl; | |
})(parseInt((now - this.getLastModified())/1000))); | |
} | |
clearAll() { | |
let now = Date.now(); | |
//console.log( "Clearing cache now at", new Date() ); | |
this.ls.clearAll(); | |
this.ls.set("CacheChangedLast", now); | |
} | |
clearStores(storeNames) { | |
storeNames.map( (v) => { | |
return this.ls.remove(v); | |
}) | |
} | |
clearStoresMatchingName(name) { | |
this.ls.keys().filter((v) => { | |
return new RegExp(name).test(v); | |
}).forEach((w) => { | |
return this.ls.remove(w); | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment