{"_id":"caching-map","_rev":"6-370a9248748f53bff34626351bdf0c10","name":"caching-map","description":"LRU cache for people who like ES6 and promises","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"caching-map","version":"1.0.0","description":"LRU cache for people who like ES6 and promises","main":"index.js","engines":{"name":">= 3.0.0"},"scripts":{"test":"mocha","prepublish":"npm test"},"author":{"name":"Assaf Arkin"},"license":"MIT","devDependencies":{"mocha":"^2.2.5"},"dependencies":{"lodash":"^3.10.0"},"keywords":["cache","caching","es2015","es6","in-memory","lru","lru-cache","map","ttl"],"repository":{"type":"git","url":"git+https://github.com/broadly/caching-map.git"},"gitHead":"4b5219dd80b29a037342b71c85b9a211f7b24c3d","bugs":{"url":"https://github.com/broadly/caching-map/issues"},"homepage":"https://github.com/broadly/caching-map#readme","_id":"caching-map@1.0.0","_shasum":"5031565268d5d37cdb54282ad5824264d1346406","_from":".","_npmVersion":"2.13.5","_nodeVersion":"3.0.0","_npmUser":{"name":"assaf","email":"assaf@labnotes.org"},"dist":{"shasum":"5031565268d5d37cdb54282ad5824264d1346406","tarball":"https://registry.npmjs.org/caching-map/-/caching-map-1.0.0.tgz","integrity":"sha512-8FlcqEVNxun+5dv4SdjEUfwZ/GorvzSNEFc6RUMP+CDr9zWcCyRJGQ8eXw+tlWYWuYi/QxJemGayyK+wAJm/LQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFIyZwukanRIWUvqGkhBCzPA1VoQcjw3DpmPCM/qyT/xAiEAwh82LBy/VO05wJ03iD/jTYpT6t8DryZfkJ0RrctgezE="}]},"maintainers":[{"name":"assaf","email":"assaf@labnotes.org"}]},"1.0.1":{"name":"caching-map","version":"1.0.1","description":"LRU cache for people who like ES6 and promises","main":"index.js","engines":{"name":">= 3.0.0"},"scripts":{"test":"mocha","prepublish":"npm test"},"author":{"name":"Assaf Arkin"},"license":"MIT","devDependencies":{"mocha":"^2.2.5"},"keywords":["cache","caching","es2015","es6","in-memory","lru","lru-cache","map","ttl"],"repository":{"type":"git","url":"git+https://github.com/broadly/caching-map.git"},"gitHead":"e34510ea83d078e98628144069dd23d0bd6b05fd","bugs":{"url":"https://github.com/broadly/caching-map/issues"},"homepage":"https://github.com/broadly/caching-map#readme","_id":"caching-map@1.0.1","_shasum":"51c14895bcbbe80488e7feab416ef663070e4ac9","_from":".","_npmVersion":"2.14.22","_nodeVersion":"4.4.0","_npmUser":{"name":"assaf","email":"assaf@labnotes.org"},"dist":{"shasum":"51c14895bcbbe80488e7feab416ef663070e4ac9","tarball":"https://registry.npmjs.org/caching-map/-/caching-map-1.0.1.tgz","integrity":"sha512-0CX6tIzTrfpxuD47tK08YdmqWXII2w16XzZtrScoXZ8HYNQSwXDR+mEAEQKz7HJdkcHgxSEymoQtnAW+iIf1Bw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCU7JTuz3mANse6/A3ZPY0nWpGPV/qKUwuWE4/osTmycwIhALuo2+l+2FPUOVX6wpbQR48D92vqLen1MFm0K0AMTxOC"}]},"maintainers":[{"name":"assaf","email":"assaf@labnotes.org"}],"_npmOperationalInternal":{"host":"packages-13-west.internal.npmjs.com","tmp":"tmp/caching-map-1.0.1.tgz_1458320620431_0.917319413041696"}},"1.0.2":{"name":"caching-map","version":"1.0.2","description":"LRU cache for people who like ES6 and promises","main":"index.js","engines":{"name":">= 3.0.0"},"scripts":{"test":"mocha","prepublish":"npm test"},"author":{"name":"Assaf Arkin"},"license":"MIT","devDependencies":{"mocha":"^2.2.5"},"keywords":["cache","caching","es2015","es6","in-memory","lru","lru-cache","map","ttl"],"files":["index.js","LICENSE","README.md"],"repository":{"type":"git","url":"git+https://github.com/broadly/caching-map.git"},"gitHead":"b2a3fbdc8835de4b6f74d138a84c7cf724362849","bugs":{"url":"https://github.com/broadly/caching-map/issues"},"homepage":"https://github.com/broadly/caching-map#readme","_id":"caching-map@1.0.2","_shasum":"8fab616b5ffdf11d958a20b5bfcaf7de7ddab6e8","_from":".","_npmVersion":"2.15.0","_nodeVersion":"4.4.0","_npmUser":{"name":"assaf","email":"assaf@labnotes.org"},"dist":{"shasum":"8fab616b5ffdf11d958a20b5bfcaf7de7ddab6e8","tarball":"https://registry.npmjs.org/caching-map/-/caching-map-1.0.2.tgz","integrity":"sha512-vVdlJ9bypaoMOYiLHiBibMVmpt4oLWtyNW0n9UuGVkg7rIqejsPgJjHdjd8DyjaCHOgzdalLqS60dHtZMBIOyg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCq+uwH09P9An7jIbciwRSAw/KfeOyrH86oDc0qUOjASQIgaT42HAvlJtJ9heC7Z5GzWfImqzPMKNA3PGt+bxcp6c8="}]},"maintainers":[{"name":"assaf","email":"assaf@labnotes.org"}],"_npmOperationalInternal":{"host":"packages-13-west.internal.npmjs.com","tmp":"tmp/caching-map-1.0.2.tgz_1458777293426_0.9906778221484274"}}},"readme":"# LRU cache for people who like ES6 and promises\n\nThis is an in-memory cache for JavaScript objects.  The API is similar to the\nES6 `Map` class, which is also an in-memory cache for JavaScript objects, but\nyou get a few additional features:\n\n* You can set the cache limit to 0 or Infinity, effectively enable/disable\n  caching (e.g. running code in development and production)\n* You can set the cache limit to any value between 0 and Infinity, deciding how\n  much you want to hold in memory\n* You can set the cost for each individual key, for smarter memory usage\n* You can set expiration for each individual key, afterwhich the key is no\n  longer available, making room for new keys\n* Expired keys are evicted first to make room for new keys, followed by least\n  recently used keys\n* You can iterate over all keys from most to least recently used\n* The materialize callback is easy  for caching asynchronous resources (database\n  connections, HTTP resources, etc) while avoiding * Materialize function to\n  avoid thundering herds\n\n\n## Example\n\n```js\nconst Cache = require('caching-map');\n\n// Cache 10 most recently used documents\nconst documents = new Cache(10);\n\n// If key is missing, load document from file system\ndocuments.materialize = function(filename) {\n  return promisify(fs.readFile)(filename);\n}\n\n\n// filename -> promise(Buffer)\n//\n// Returns promise that resolves to the content of this file\n// File becomes the most recently used\nfunction loadDocument(filename) {\n  return documents.get(filename);\n}\n\n\n// -> [ filename ]\n//\n// Returns up to ten filenames of the most recently loaded documents\nfunction listDocuments() {\n  const filenames = [ ...documents.keys() ];\n  return filenames;\n}\n```\n\n\n### Limit and Cost\n\nWhen creating a new cache, the first constructor argument is the cache limit.\n\nThe second argument can be another cache, a `Map`, or any iterator that returns\nname/value pairs.  You can easily create a new cache from a map (`new Cache(limit,\nmap)`), or turn a cache into a map (`new Map(cache)`).\n\nIf you set the cache limit to zero (or negative number), it will hold zero keys.\nThis could be useful when you want to use the same object in different\nconfigurations, e.g. cache in production but always live load in development.\n\nIf you set the cache limit to infinity, it will hold as many keys as you've got.\nThis is useful if you want cache features, but don't care about memory usage.\nFor example, flipping between caching all or nothing, using TTL to expire old\nvalues, or tracking most recently used keys:\n\n```js\n// Cache keys in production, always live load in development\n// For example, for caching templates\nconst limit = (NODE.ENV === 'production') ? Infinity : 0;\nconst cache = new Cache(limit);\n```\n\nYou can use the `limit` property to change the cache limit at any time.\nChanging the limit doesn't evict any keys until the cache needs to make room for\nnew keys.\n\n\n### Setting Keys\n\nWhen you set a key, that key becomes the most recently used.\n\nWhen you set a key, if the cache runs into its storage limit, it will start\nevicting (deleting) keys until it has room to store the new key.  It will first\nevict any expired keys, and then evict the least recently used keys.\n\nWhen setting a key, you can associate a cost for that key.  The default is one,\nso the default behavior is to limit the number of keys stored in the cache:\n\n```js\ncache.limit = 2;\ncache\n  .set('x', 'XXX')\n  .set('y', 'YYY')\n  .set('z', 'ZZZ');\ncache.size\n=> 2\n[ ...cache.keys() ]\n=> [ 'z', 'y' ]\n```\n\nHowever, if you are able to calculate a more accurate cost for each of the keys\n(e.g. the size of a string), you can use that for better memory usage:\n\n```js\nconst x = 'X';\nconst y = 'YYYY';\n\ncache.set('x', x, { cost: Buffer.byteLength(x) });\n[ cache.size, cache.cost ]\n=> [ 1, 1 ]\n\ncache.set('y', y, { cost: Buffer.byteLength(y) });\n[ cache.size, cache.cost ]\n=> [ 2, 5 ]\n```\n\nWhen setting a key, you can associate the time to live (in milliseconds).  Once\nthat time has passed, the key is expired.  Expired keys are removed first to\nmake room for new keys.  There is no way to retrieve the value of an expired\nkey:\n\n```js\nconst ttl = ms('1h');\n\ncache.set('key', 'good for an hour', { ttl });\ncache.get('key');\n=> 'good for an hour'\n\nsetTimeout(function() {\n  cache.get('key');\n}, ttl);\n=> undefined\n```\n\nIf a key expires immediately (TTL is zero or negative), or if the key cost is\nlarger than the limit, then that key is not stored, and no other key is evicted.\n\n\n### Get\n\nWhen you retrieve a key (`get(key)`), that key becomes the most recently used\nkey.  It will be the last key removed to make room for new keys, and the first\nkey returned when iterating through the keys.\n\nIn contrast, checking whether a key exists (`has(key)`), or iterating over keys,\ndoes not change their order.  Only getting or setting a key changes it to most\nrecent.\n\n\n### Iterate\n\nThe default iterator, `entries()`, `keys()` and `values()` are all available, as\nwell as `forEach`.  Since this is an LRU cache, they all iterate on entries\nbased on their caching order: from most to least recently used.\n\nYou can use iteration for operations like deleting keys based on a pattern,\nlisting all keys, and so forth:\n\n```js\nfunction deleteKeysInNamespace(cache, namespace) {\n  const prefix = `${namespace}:`;\n  for (let key of cache)\n    if (key.startsWith(prefix))\n      cache.delete(key);\n}\n\nfunction listAllKeys(cache) {\n  return [ ...cache.keys() ];\n}\n```\n\nJust watch out, iteration is O(N), and will be expensive for caches with many\nkeys.\n\n\n### Lazy Expiration\n\nExpired keys are lazily evicted from the cache, either to make room for new\nkeys, or when attempting to retrieve, check existence or iterate over the\nexpired key.\n\nIf you want to force evict all expired keys, you need to do so yourself, by\niterating over all keys:\n\n```js\nfunction evictExpiredKeys() {\n  // Iterating over expired key removes it from the cache\n  for (let entry of cache) ;\n}\n\nsetTimeout(evictExpiredKeys, ms('5m'));\n```\n\nDon't forget that whenever you read the `size` or `cost` of the cache, that\nvalue may include expired keys that are still in the cache but no longer\naccessible.\n\n\n### The Materialize Function\n\nA common pattern for caching code is to retrieve a key, and when the key doesn't\nexist, resolve and store the value.  This easily leads to the [Thundering herd\nproblem](https://en.wikipedia.org/wiki/Thundering_herd_problem).\n\nFor example, if you have 100 concurrent requests that all need to render the\nsame data, but the cache is empty, you may end up with 100 database queries\nattempting to set a single cache key.\n\nThe simplest solution is to cache a promise that resolves to that value.  That\nway, everyone is waiting for that one promise to resolve once.  However, if an\nerror occurs and the promise is rejected, you want to remove it from the cache,\nso a new promise can take its place.\n\nThe materialize function is a convenient way to implement this pattern.  When a\nkey has no value, this function is called with the key, and should return the\nexpected value, or a promise that resolves to that value.  For example:\n\n```js\ncache.materialize = function(url) {\n  return promisify(request)(url);\n};\n\nconst URL = 'http://example.com/';\n\ncache.get(URL).then(\n  function(result) {\n    // We cached a promise that always resolves to this response\n    console.log(result.body);\n\n    assert( cache.has(URL) );\n  },\n  function(error) {\n    // The promise is no longer in the cache, we can try again\n    assert( !cache.has(URL) );\n  });\n\n```\n\nIf you want to set the cost and/or expiration for that key, returns a promise,\nbut also set the key when that promise resolves:\n\n```js\ncache.materialize = function(url) {\n  const promise = promisify(request)(url);\n\n  promise.then(function(response) {\n\n    const cost = response.body.length;\n    cache.set(url, promise, { cost });\n\n  });\n  return promise;\n};\n```\n\n\n## License\n\nMIT License Copyright (c) 2015 Broadly Inc\n","maintainers":[{"name":"assaf","email":"assaf@labnotes.org"}],"time":{"modified":"2022-06-13T05:23:58.705Z","created":"2015-08-18T04:29:57.925Z","1.0.0":"2015-08-18T04:29:57.925Z","1.0.1":"2016-03-18T17:03:40.801Z","1.0.2":"2016-03-23T23:54:55.768Z"},"homepage":"https://github.com/broadly/caching-map#readme","keywords":["cache","caching","es2015","es6","in-memory","lru","lru-cache","map","ttl"],"repository":{"type":"git","url":"git+https://github.com/broadly/caching-map.git"},"author":{"name":"Assaf Arkin"},"bugs":{"url":"https://github.com/broadly/caching-map/issues"},"license":"MIT","readmeFilename":"README.md","users":{"morewry":true}}