Last active
December 1, 2023 12:21
-
-
Save lesleh/9d66bc87f22bf5e28997 to your computer and use it in GitHub Desktop.
Basic memory cache implementation for JavaScript.
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
function Cache(config) { | |
config = config || {}; | |
config.trim = config.trim || 600; | |
config.ttl = config.ttl || 3600; | |
var data = {}; | |
var self = this; | |
var now = function() { | |
return new Date().getTime() / 1000; | |
}; | |
/** | |
* Object for holding a value and an expiration time | |
* @param expires the expiry time as a UNIX timestamp | |
* @param value the value of the cache entry | |
* @constructor ¯\(°_o)/¯ | |
*/ | |
var CacheEntry = function(expires, value) { | |
this.expires = expires; | |
this.value = value; | |
}; | |
/** | |
* Creates a new cache entry with the current time + ttl as the expiry. | |
* @param value the value to set in the entry | |
* @returns {CacheEntry} the cache entry object | |
*/ | |
CacheEntry.create = function(value) { | |
return new CacheEntry(now() + config.ttl, value); | |
}; | |
/** | |
* Returns an Array of all currently set keys. | |
* @returns {Array} cache keys | |
*/ | |
this.keys = function() { | |
var keys = []; | |
for(var key in data) | |
if (data.hasOwnProperty(key)) | |
keys.push(key); | |
return keys; | |
}; | |
/** | |
* Checks if a key is currently set in the cache. | |
* @param key the key to look for | |
* @returns {boolean} true if set, false otherwise | |
*/ | |
this.has = function(key) { | |
return data.hasOwnProperty(key); | |
}; | |
/** | |
* Clears all cache entries. | |
*/ | |
this.clear = function() { | |
for(var key in data) | |
if (data.hasOwnProperty(key)) | |
self.remove(key); | |
}; | |
/** | |
* Gets the cache entry for the given key. | |
* @param key the cache key | |
* @returns {*} the cache entry if set, or undefined otherwise | |
*/ | |
this.get = function(key) { | |
return data[key].value; | |
}; | |
/** | |
* Returns the cache entry if set, or a default value otherwise. | |
* @param key the key to retrieve | |
* @param def the default value to return if unset | |
* @returns {*} the cache entry if set, or the default value provided. | |
*/ | |
this.getOrDefault = function(key, def) { | |
return self.has(key) ? data[key].value : def; | |
}; | |
/** | |
* Sets a cache entry with the provided key and value. | |
* @param key the key to set | |
* @param value the value to set | |
*/ | |
this.set = function(key, value) { | |
data[key] = CacheEntry.create(value); | |
}; | |
/** | |
* Removes the cache entry for the given key. | |
* @param key the key to remove | |
*/ | |
this.remove = function(key) { | |
delete data[key]; | |
}; | |
/** | |
* Checks if the cache entry has expired. | |
* @param entrytime the cache entry expiry time | |
* @param curr (optional) the current time | |
* @returns {boolean} true if expired, false otherwise | |
*/ | |
this.expired = function(entrytime, curr) { | |
if(!curr) | |
curr = now(); | |
return entrytime < curr; | |
}; | |
/** | |
* Trims the cache of expired keys. This function is run periodically (see config.ttl). | |
*/ | |
this.trim = function() { | |
var curr = now(); | |
for (var key in data) | |
if (data.hasOwnProperty(key)) | |
if(self.expired(data.expires, curr)) | |
self.remove(key); | |
}; | |
// Periodical cleanup | |
setInterval(this.trim, config['trim'] * 1000); | |
//-------------------------------------------------------- | |
// Events | |
var eventCallbacks = {}; | |
this.on = function(event, callback) { | |
// TODO handle event callbacks | |
}; | |
} | |
module.exports = Cache; |
Also here's a pretty nice and common use case
this.getOrCreate = function(key, fn) {
if (self.has(key)) {
return self.get(key);
}
const value = fn();
self.set(key, value);
return value;
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice simple solution, but there is a small mistake, line 118 should be
if(self.expired(data[key].expires, curr))