I went to look how the library accounted for these issues and it does not. I didn’t look to see if it uses timer coalescing or intervals, I wouldn’t want O(millions) of setTimout calls on my service either.
I think it’s fine to use in the browser or a hobby server, but due to the limitations of Map I would not use it in my production server.
Redis can do 2^32 = 4,294,967,296 keys (a few more), and you can do the “multi level map” by sharding your key space across multiple Redis or Memcached processes. Redis et al also has a large advantage of the cache surviving application deploy. Again, not everyone needs this but to me the main benefit of a remote cache is consistently lowering latencies, versus a in-memory cache where your latency will spike after every deploy as the cache refills.
const store = new Map();
const expiryTimes = new Map();
function get(key) {
// (This works even for non-expiring keys because undefined is not less than any number.)
if (expiryTimes.get(key) < Date.now()) {
store.delete(key);
}
return store.get(key);
}
function set(key, value, expiry) {
store.set(key, value);
if (expiry) {
expiryTimes.set(expiry);
}
}
function del(key) {
store.delete(key);
expiryTimes.delete(key);
}
function flushExpired() {
const now = Date.now();
for (const [key, time] of expiryTimes) {
if (time < now) {
del(key);
}
}
}
// Optional: automatically delete expired entries to free memory, once a second since that’s what KV.js does, but that’s probably waaaaay more often than you need.
setInterval(flushExpired, 1000);
Working directly with store and expiryTimes for more advanced stuff will genuinely regularly be easier than working with the KV.js abstraction.Very often I agree with you about the dangers of writing it yourself. But very often I also sufficiently dislike how libraries are implemented, with unnecessary bloat like excessive flexibility (all the options and such) or explicit runtime type checking rather than just letting things go wonky or blow up if given bad data.
In reality, in a case like this I would actually recommend something other than a generic container. Non-expiring keys? Use variables if the keys are a finite set of known values, or a Map if the keys are in fact arbitrary. Expiring keys? Use something vaguely like this, but probably wrapping Map<K, [number, V]>, made simpler by not supporting non-expiring keys (which mixture was what caused my bug, and which mixture I was never fond of).
Is an in-process, in-memory database faster than making a query over network? Yes it is.
const KV = {};
KV["credentials"] = {access_key: "XXXX", secret: "YYYY"};
console.log(KV["credentials"].secret);
The point was that “just use redis” is a poor and incorrect advice.
https://narma.github.io/2015/redis-in-browser/
https://medium.com/fluence-network/porting-redis-to-webassem...
If you look at the code; it's literally just a map with some function around it. If you end up in a situation where you feel the need to wrap a map with some function to handle some typical needs (eg: access a random key; manage a ttl/expire for a key; ...) you might as well be using this.
The fact that the name of the functions have been taken from redis means that if/when you move to an external KV store, the transition will be trivial. It also means you don't really need to learn it if you already know redis.
I don't see becoming the #1 library on npm; with conferences and speakers debating the intricacies of its architecture. But hey it might solve someones need.