@isaacs/ttlcache
Advanced tools
Comparing version 1.1.0 to 1.2.0
@@ -7,3 +7,3 @@ // Type definitions for ttlcache 1.0.0 | ||
declare class TTLCache<K, V> implements Iterable<[K, V]> { | ||
constructor(options: TTLCache.Options<K, V>) | ||
constructor(options?: TTLCache.Options<K, V>) | ||
@@ -108,5 +108,6 @@ /** | ||
* | ||
* Must be an integer number of ms, defaults to 0, which means "no TTL" | ||
* Must be an integer number of ms, or Infinity. Defaults to `undefined`, | ||
* meaning that a TTL must be set explicitly for each set() | ||
*/ | ||
ttl: number | ||
ttl?: number | ||
@@ -159,3 +160,12 @@ /** | ||
noDisposeOnSet?: boolean | ||
/** | ||
* Do not update the TTL when overwriting an existing item. | ||
*/ | ||
noUpdateTTL?: boolean | ||
/** | ||
* Override the default TTL for this one set() operation. | ||
* Required if a TTL was not set in the constructor options. | ||
*/ | ||
ttl?: number | ||
@@ -166,3 +176,3 @@ } | ||
/** | ||
* Update the age of items | ||
* Update the age of item being retrieved. | ||
*/ | ||
@@ -169,0 +179,0 @@ updateAgeOnGet?: boolean |
46
index.js
@@ -13,4 +13,6 @@ // A simple TTL cache with max capacity option, ms resolution, | ||
} | ||
const { now } = maybeReqPerfHooks(Date) | ||
const timeProvider = maybeReqPerfHooks(Date) | ||
const now = () => timeProvider.now() | ||
const isPosInt = n => n && n === Math.floor(n) && n > 0 && isFinite(n) | ||
const isPosIntOrInf = n => n === Infinity || isPosInt(n) | ||
@@ -24,3 +26,3 @@ class TTLCache { | ||
dispose, | ||
}) { | ||
} = {}) { | ||
// {[expirationTime]: [keys]} | ||
@@ -32,6 +34,8 @@ this.expirations = Object.create(null) | ||
this.expirationMap = new Map() | ||
if (ttl !== undefined && !isPosInt(ttl)) { | ||
throw new TypeError('ttl must be positive integer if set') | ||
if (ttl !== undefined && !isPosIntOrInf(ttl)) { | ||
throw new TypeError( | ||
'ttl must be positive integer or Infinity if set' | ||
) | ||
} | ||
if (!isPosInt(max) && max !== Infinity) { | ||
if (!isPosIntOrInf(max)) { | ||
throw new TypeError('max must be positive integer or Infinity') | ||
@@ -62,3 +66,3 @@ } | ||
setTTL (key, ttl = this.ttl) { | ||
setTTL(key, ttl = this.ttl) { | ||
const current = this.expirationMap.get(key) | ||
@@ -75,11 +79,15 @@ if (current !== undefined) { | ||
const expiration = Math.floor(now() + ttl) | ||
this.expirationMap.set(key, expiration) | ||
if (!this.expirations[expiration]) { | ||
const t = setTimeout(() => this.purgeStale(), ttl) | ||
/* istanbul ignore else - affordance for non-node envs */ | ||
if (t.unref) t.unref() | ||
this.expirations[expiration] = [] | ||
if (ttl !== Infinity) { | ||
const expiration = Math.floor(now() + ttl) | ||
this.expirationMap.set(key, expiration) | ||
if (!this.expirations[expiration]) { | ||
const t = setTimeout(() => this.purgeStale(), ttl) | ||
/* istanbul ignore else - affordance for non-node envs */ | ||
if (t.unref) t.unref() | ||
this.expirations[expiration] = [] | ||
} | ||
this.expirations[expiration].push(key) | ||
} else { | ||
this.expirationMap.set(key, Infinity) | ||
} | ||
this.expirations[expiration].push(key) | ||
} | ||
@@ -96,4 +104,4 @@ | ||
) { | ||
if (!isPosInt(ttl)) { | ||
throw new TypeError('ttl must be positive integer') | ||
if (!isPosIntOrInf(ttl)) { | ||
throw new TypeError('ttl must be positive integer or Infinity') | ||
} | ||
@@ -130,3 +138,5 @@ if (this.expirationMap.has(key)) { | ||
const expiration = this.expirationMap.get(key) | ||
return expiration !== undefined | ||
return expiration === Infinity | ||
? expiration | ||
: expiration !== undefined | ||
? Math.max(0, Math.ceil(expiration - now())) | ||
@@ -198,3 +208,3 @@ : 0 | ||
for (const exp in this.expirations) { | ||
if (exp > n) { | ||
if (exp === 'Infinity' || exp > n) { | ||
return | ||
@@ -201,0 +211,0 @@ } |
{ | ||
"name": "@isaacs/ttlcache", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"files": [ | ||
@@ -5,0 +5,0 @@ "index.js", |
@@ -57,5 +57,10 @@ # @isaacs/ttlcache | ||
* `max` The max number of items to keep in the cache. | ||
* `max` The max number of items to keep in the cache. Must be | ||
positive integer or `Infinity`, defaults to `Infinity` (ie, | ||
limited only by TTL, not by item count). | ||
* `ttl` The max time in ms to store items. Overridable on the `set()` | ||
method. | ||
method. Must be a positive integer or `Infinity` (see note | ||
below about immortality hazards). If `undefined` in | ||
constructor, then a TTL _must_ be provided in each `set()` | ||
call. | ||
* `updateAgeOnGet` Should the age of an item be updated when it is | ||
@@ -108,2 +113,9 @@ retrieved? Defaults to `false`. Overridable on the `get()` method. | ||
Note that using `updateAgeOnGet` _can_ effectively simulate a | ||
"least-recently-used" type of algorithm, by repeatedly updating | ||
the TTL of items as they are used. However, if you find yourself | ||
doing this, consider using | ||
[`lru-cache`](http://npm.im/lru-cache), as it is much more | ||
optimized for an LRU use case. | ||
### `cache.getRemainingTTL(key)` | ||
@@ -193,1 +205,15 @@ | ||
setting to a new value), it is deleted and re-inserted. | ||
## Immortality Hazards | ||
It is possible to set a TTL of `Infinity`, in which case an item | ||
will never expire. As it does not expire, its TTL is not | ||
tracked, and `getRemainingTTL()` will return `Infinity` for that | ||
key. | ||
If you do this, then the item will never be purged. Create | ||
enough immortal values, and the cache will grow to consume all | ||
available memory. If find yourself doing this, it's _probably_ | ||
better to use a different data structure, such as a `Map` or | ||
plain old object to store values, as it will have better | ||
performance and the hazards will be more obvious. |
20233
379
217