Skip to content

Instantly share code, notes, and snippets.

@BluSyn
Created January 26, 2019 09:04
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 BluSyn/2033c1f74765d0fbdd91571e4518bd15 to your computer and use it in GitHub Desktop.
Save BluSyn/2033c1f74765d0fbdd91571e4518bd15 to your computer and use it in GitHub Desktop.
/**
* cache.js - es6 proxy cacher
* Copyright (c) 2019, Steven Bower (MIT License).
*/
'use strict';
/**
* Cache for Clients and Wallets
* Use with ES6 Proxy:
* eg, new Proxy(WalletClient, new Cache());
*
* Cache key is serialized as: 'fuction__'+args.join('')
* example: client.getAccount('myaccount')
* is stored in Key "getaccountmyaccount"
*
* Note: You can force reset cache by calling __method,
* example: client.__getAccount()
*
* TODO: cache timestamp and auto-reload stale data?
*/
class Cache {
constructor(options) {
options = options || {};
this.cache = {};
this.timer = {};
// Cache time for individual keys (in ms)
// 0 or false to disable
this.timeout = Number(options.timeout) || false;
// Object depth limit when generating cache keys
this.keyDepth = Number(options.keyDepth) || 4;
}
clear() {
this.cache = {};
}
get(target, prop, receiver) {
if (typeof target[prop] !== 'function')
return target[prop];
let reset = (prop.substr(0, 2) === '__');
prop = reset ? prop.substr(2) : prop;
return async (...args) => {
const key = prop + '__' + this.genKey(args);
const timed = this.timeout &&
(new Date().getTime() - this.timer[key]) >= this.timeout;
if (!reset && !timed && this.cache[key]) {
return this.clone(this.cache[key]);
}
const data = await target[prop](...args);
this.cache[key] = data;
this.timer[key] = new Date().getTime();
return this.clone(data);
};
}
// cached results should return clone of data
// so data can't be accidentally mutated
clone(obj) {
if (!obj || typeof obj !== 'object')
return obj;
return Array.isArray(obj) ?
[...obj] : JSON.parse(JSON.stringify(obj));
}
genKey(obj, depth) {
// "falsey" values should still return differently
if (!obj)
return obj;
depth = depth ? depth + 1 : 1;
if (depth > this.keyDepth)
return '';
if (Array.isArray(obj)) {
return (obj.map(o => this.genKey(o, depth))).join('');
}
switch (typeof obj) {
case 'function':
return 'fn';
case 'object':
return Object.keys(obj)
.map((key) => {
return key + this.genKey(obj[key], depth);
}).join('');
default:
return obj;
}
}
}
module.exports = Cache;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment