@isaacs/ttlcache 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -53,9 +53,9 @@ where the `setTimeout` method does not return an object with an
53
53
  `unref()` method, the process will stay open as long as any
54
54
  unexpired entry exists in the cache.
55
55
 
56
- You may delete all entries (by using `cache.clear()` or
57
- `cache.delete(key)` with every key) in order to clear the
58
- timeouts and allow the process to exit normally.
56
+ You may call `cache.cancelTimer()` to clear the timeout and
57
+ allow the process to exit normally. Be advised that canceling the
58
+ timer in this way will of course prevent anything from expiring.
59
59
 
60
60
  ## API
61
61
 
@@ -164,6 +164,14 @@ latest expiring.
164
164
  Return an iterator that walks through each `value` from soonest expiring to
165
165
  latest expiring.
166
166
 
167
+ ### `cache.cancelTimer()`
168
+
169
+ Clear the internal timer, and stop automatically expiring items
170
+ when their TTL expires.
171
+
172
+ This allows the process to exit normally on Deno and other
173
+ platforms that lack Node's `Timer.unref()` method.
174
+
167
175
  ## Internal Methods
168
176
 
169
177
  You should not ever call these, they are managed automatically.
@@ -188,6 +196,13 @@ automatically.
188
196
  Called when an item is removed from the cache and should be disposed. Set
189
197
  this on the constructor options.
190
198
 
199
+ ### `setTimer`
200
+
201
+ **Internal**
202
+
203
+ Called when an with a ttl is added. This ensures that only one timer
204
+ is setup at once. Called automatically.
205
+
191
206
  ## Algorithm
192
207
 
193
208
  The cache uses two `Map` objects. The first maps item keys to their
package/index.d.ts CHANGED
@@ -86,10 +86,17 @@ declare class TTLCache<K, V> implements Iterable<[K, V]> {
86
86
  * `cache.entries()`
87
87
  */
88
88
  public [Symbol.iterator](): Iterator<[K, V]>
89
+
90
+ /**
91
+ * Cancel the timer and stop automatically expiring entries.
92
+ * This allows the process to gracefully exit where Timer.unref()
93
+ * is not available.
94
+ */
95
+ public cancelTimer(): void
89
96
  }
90
97
 
91
98
  declare namespace TTLCache {
92
- type DisposeReason = 'evict' | 'set' | 'delete'
99
+ type DisposeReason = 'evict' | 'set' | 'delete' | 'stale'
93
100
 
94
101
  type Disposer<K, V> = (
95
102
  value: V,
package/index.js CHANGED
@@ -3,12 +3,14 @@
3
3
  // Relies on the fact that integer Object keys are kept sorted,
4
4
  // and managed very efficiently by V8.
5
5
 
6
+ /* istanbul ignore next */
6
7
  const perf =
7
8
  typeof performance === 'object' &&
8
9
  performance &&
9
10
  typeof performance.now === 'function'
10
11
  ? performance
11
12
  : Date
13
+
12
14
  const now = () => perf.now()
13
15
  const isPosInt = n => n && n === Math.floor(n) && n > 0 && isFinite(n)
14
16
  const isPosIntOrInf = n => n === Infinity || isPosInt(n)
@@ -48,19 +50,54 @@ class TTLCache {
48
50
  this.dispose = dispose
49
51
  }
50
52
 
51
- this.timers = new Set()
53
+ this.timer = undefined
54
+ this.timerExpiration = undefined
55
+ }
56
+
57
+ setTimer (expiration, ttl) {
58
+ if (this.timerExpiration < expiration) {
59
+ return
60
+ }
61
+
62
+ if (this.timer) {
63
+ clearTimeout(this.timer)
64
+ }
65
+
66
+ const t = setTimeout(() => {
67
+ this.timer = undefined
68
+ this.timerExpiration = undefined
69
+ this.purgeStale()
70
+ for (const exp in this.expirations) {
71
+ this.setTimer(exp, exp - now())
72
+ break
73
+ }
74
+ }, ttl)
75
+
76
+ /* istanbul ignore else - affordance for non-node envs */
77
+ if (t.unref) t.unref()
78
+
79
+ this.timerExpiration = expiration
80
+ this.timer = t
52
81
  }
53
82
 
54
83
  // hang onto the timer so we can clearTimeout if all items
55
84
  // are deleted. Deno doesn't have Timer.unref(), so it
56
85
  // hangs otherwise.
57
- cancelTimers() {
58
- for (const t of this.timers) {
59
- clearTimeout(t)
60
- this.timers.delete(t)
86
+ cancelTimer() {
87
+ if (this.timer) {
88
+ clearTimeout(this.timer)
89
+ this.timerExpiration = undefined
90
+ this.timer = undefined
61
91
  }
62
92
  }
63
93
 
94
+ /* istanbul ignore next */
95
+ cancelTimers() {
96
+ process.emitWarning('TTLCache.cancelTimers has been renamed to ' +
97
+ 'TTLCache.cancelTimer (no "s"), and will be removed in the next ' +
98
+ 'major version update')
99
+ return this.cancelTimer()
100
+ }
64
101
 
65
102
  clear() {
66
103
  const entries =
@@ -68,7 +105,7 @@ class TTLCache {
68
105
  this.data.clear()
69
106
  this.expirationMap.clear()
70
107
  // no need for any purging now
71
- this.cancelTimers()
108
+ this.cancelTimer()
72
109
  this.expirations = Object.create(null)
73
110
  for (const [key, val] of entries) {
74
111
  this.dispose(val, key, 'delete')
@@ -91,14 +128,8 @@ class TTLCache {
91
128
  const expiration = Math.floor(now() + ttl)
92
129
  this.expirationMap.set(key, expiration)
93
130
  if (!this.expirations[expiration]) {
94
- const t = setTimeout(() => {
95
- this.timers.delete(t)
96
- this.purgeStale()
97
- }, ttl)
98
- /* istanbul ignore else - affordance for non-node envs */
99
- if (t.unref) t.unref()
100
- this.timers.add(t)
101
131
  this.expirations[expiration] = []
132
+ this.setTimer(expiration, ttl)
102
133
  }
103
134
  this.expirations[expiration].push(key)
104
135
  } else {
@@ -184,7 +215,7 @@ class TTLCache {
184
215
  }
185
216
  this.dispose(value, key, 'delete')
186
217
  if (this.size === 0) {
187
- this.cancelTimers()
218
+ this.cancelTimer()
188
219
  }
189
220
  return true
190
221
  }
@@ -244,7 +275,7 @@ class TTLCache {
244
275
  }
245
276
  }
246
277
  if (this.size === 0) {
247
- this.cancelTimers()
278
+ this.cancelTimer()
248
279
  }
249
280
  }
250
281
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isaacs/ttlcache",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "files": [
5
5
  "index.js",
6
6
  "index.d.ts"