@wfp99/async-lru-cache 1.0.0 → 1.1.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
@@ -12,9 +12,51 @@ An asynchronous LRU (Least Recently Used) memory cache that supports asynchronou
12
12
  - 🔄 **Automatic Merging**: Automatically merges concurrent GET requests for the same key
13
13
  - 📝 **Serialized Writes**: Serializes PUT operations for the same key to ensure execution order
14
14
  - 🗑️ **LRU Eviction**: Implements LRU algorithm to automatically remove least recently used items
15
+ - ⏰ **TTL Support**: Automatic expiration of cache entries with configurable Time To Live
15
16
  - 🛡️ **Error Handling**: Comprehensive error handling with automatic cache cleanup on failures
16
17
  - 🧹 **Complete Clearing**: Support for clearing all cache entries at once
17
18
 
19
+ ## Why AsyncLRUCache?
20
+
21
+ ### The Problem
22
+ Traditional caching solutions often struggle with asynchronous operations:
23
+ - **Race Conditions**: Multiple concurrent requests for the same resource can trigger duplicate expensive operations
24
+ - **Memory Leaks**: Failed operations may leave stale entries in cache without proper cleanup
25
+ - **Complex State Management**: Coordinating cache updates with external persistence layers becomes error-prone
26
+ - **External Dependencies**: Many caching solutions require external services (Redis, Memcached) adding infrastructure complexity, network latency, and deployment overhead
27
+
28
+ ### The Solution
29
+ AsyncLRUCache addresses these challenges by providing:
30
+ - **Smart Request Merging**: Multiple concurrent GET calls for the same key automatically share a single loader execution
31
+ - **Automatic Error Recovery**: Failed operations are automatically cleaned up, preventing memory leaks and stale data
32
+ - **Operation Serialization**: PUT operations for the same key are queued and executed sequentially, ensuring data consistency
33
+ - **Zero External Dependencies**: Pure in-memory solution eliminates the need for external caching services, reducing infrastructure complexity, setup overhead, and network latency while increasing reliability and performance
34
+
35
+ ### When to Use
36
+ AsyncLRUCache is perfect for scenarios involving:
37
+ - **API Response Caching**: Cache expensive HTTP requests with automatic deduplication
38
+ - **Database Query Results**: Reduce database load while maintaining data consistency
39
+ - **Computed Values**: Cache expensive calculations with built-in invalidation
40
+ - **File System Operations**: Cache file reads/writes with persistence hooks
41
+ - **Microservices Communication**: Reduce inter-service calls with intelligent caching
42
+
43
+ ### Why Choose In-Memory Over External Cache Services?
44
+
45
+ **Simplicity & Performance**
46
+ - **No Setup Required**: Install and use immediately without configuring external services
47
+ - **Zero Network Latency**: Direct memory access provides microsecond response times
48
+ - **Reduced Infrastructure**: Eliminate cache servers, reducing operational complexity and costs
49
+
50
+ **Reliability & Predictability**
51
+ - **No Network Dependencies**: Cache operations never fail due to network issues
52
+ - **Consistent Performance**: No variable network latency affecting cache performance
53
+ - **Simplified Deployment**: Deploy as part of your application without managing separate cache infrastructure
54
+
55
+ **Development Efficiency**
56
+ - **Instant Development**: Start coding immediately without setting up Redis, Memcached, etc.
57
+ - **Easy Testing**: Unit tests run without external service dependencies
58
+ - **Simplified Debugging**: Cache behavior is predictable and traceable within your application process
59
+
18
60
  ## Installation
19
61
 
20
62
  ```bash
@@ -64,6 +106,59 @@ try {
64
106
  }
65
107
  ```
66
108
 
109
+ ### TTL (Time To Live) Support
110
+
111
+ AsyncLRUCache supports automatic expiration of cache entries using TTL (Time To Live):
112
+
113
+ ```typescript
114
+ import { AsyncLRUCache } from '@wfp99/async-lru-cache';
115
+
116
+ // Create cache with TTL support
117
+ const cache = new AsyncLRUCache({
118
+ capacity: 100,
119
+ defaultTtlMs: 5000, // Default TTL of 5 seconds
120
+ cleanupIntervalMs: 10000 // Cleanup expired entries every 10 seconds
121
+ });
122
+
123
+ // Use default TTL
124
+ const data1 = await cache.get('key1', async () => {
125
+ return await fetchData();
126
+ });
127
+
128
+ // Override TTL for specific entries
129
+ const data2 = await cache.get('key2', async () => {
130
+ return await fetchCriticalData();
131
+ }, 30000); // 30 seconds TTL
132
+
133
+ // Put with custom TTL
134
+ await cache.put('key3', value, async (key, val) => {
135
+ await saveToDb(key, val);
136
+ }, 60000); // 1 minute TTL
137
+
138
+ // Manual cleanup of expired entries
139
+ cache.cleanupExpired();
140
+
141
+ // Check if key exists and is not expired
142
+ if (cache.has('key1')) {
143
+ console.log('Key exists and is valid');
144
+ }
145
+
146
+ // Get cache size
147
+ console.log('Current cache size:', cache.size());
148
+
149
+ // Destroy cache (stops cleanup timer and clears all data)
150
+ cache.destroy();
151
+ ```
152
+
153
+ #### TTL Configuration Options
154
+
155
+ - **`defaultTtlMs`**: Default TTL for all cache entries (optional)
156
+ - **`cleanupIntervalMs`**: Automatic cleanup interval for expired entries (optional)
157
+ - Individual `get()` and `put()` methods accept TTL overrides
158
+ - Expired entries are automatically removed during normal operations
159
+ - Call `cleanupExpired()` for manual cleanup
160
+ - Call `destroy()` to stop timers and prevent memory leaks
161
+
67
162
  ### Advanced Usage
68
163
 
69
164
  ```typescript
package/README.zh-TW.md CHANGED
@@ -8,9 +8,51 @@
8
8
  - 🔄 **自動合併**:自動合併相同 key 的並發 GET 請求
9
9
  - 📝 **序列化寫入**:序列化同一 key 的 PUT 操作,確保順序執行
10
10
  - 🗑️ **LRU 淘汰策略**:實現 LRU 演算法,自動移除最久未使用的項目
11
+ - ⏰ **TTL 支援**:支援可配置的生存時間(Time To Live),自動過期快取項目
11
12
  - 🛡️ **錯誤處理**:完善的錯誤處理機制,載入或保存失敗時自動清理快取
12
13
  - 🧹 **完整清除**:支援一次性清除所有快取項目
13
14
 
15
+ ## 為什麼選擇 AsyncLRUCache?
16
+
17
+ ### 問題所在
18
+ 傳統的快取解決方案在處理非同步操作時經常遇到困難:
19
+ - **競態條件**:對同一資源的多個並發請求可能觸發重複的昂貴操作
20
+ - **記憶體洩漏**:失敗的操作可能在快取中留下過期項目而沒有適當的清理
21
+ - **複雜的狀態管理**:協調快取更新與外部持久化層變得容易出錯
22
+ - **外部依賴**:許多快取解決方案需要外部服務(Redis、Memcached),增加基礎架構複雜性、網路延遲和部署成本
23
+
24
+ ### 解決方案
25
+ AsyncLRUCache 透過以下方式解決這些挑戰:
26
+ - **智慧請求合併**:對同一 key 的多個並發 GET 呼叫自動共享單一載入器執行
27
+ - **自動錯誤恢復**:失敗的操作會自動清理,防止記憶體洩漏和過期資料
28
+ - **操作序列化**:同一 key 的 PUT 操作會排隊並依序執行,確保資料一致性
29
+ - **零外部依賴**:純記憶體內解決方案,無需外部快取服務,減少基礎架構複雜性、設定成本和網路延遲,同時提高可靠性和效能
30
+
31
+ ### 適用場景
32
+ AsyncLRUCache 非常適合以下情境:
33
+ - **API 回應快取**:快取昂貴的 HTTP 請求並自動去重複
34
+ - **資料庫查詢結果**:減少資料庫負載同時維持資料一致性
35
+ - **計算值**:快取昂貴的計算結果並內建失效機制
36
+ - **檔案系統操作**:快取檔案讀寫並提供持久化串接
37
+ - **微服務通訊**:透過快取減少服務間呼叫
38
+
39
+ ### 為什麼選擇記憶體內快取而非外部快取服務?
40
+
41
+ **簡單性與效能**
42
+ - **無需設定**:安裝後立即使用,無需配置外部服務
43
+ - **零網路延遲**:直接記憶體存取提供微秒級回應時間
44
+ - **簡化基礎架構**:省去快取伺服器,減少營運複雜性和成本
45
+
46
+ **可靠性與可預測性**
47
+ - **無網路依賴**:快取操作不會因網路問題而失敗
48
+ - **一致性效能**:沒有可變的網路延遲影響快取效能
49
+ - **簡化部署**:作為應用程式的一部分部署,無需管理獨立的快取基礎架構
50
+
51
+ **開發效率**
52
+ - **即時開發**:無需設定 Redis、Memcached 等即可開始編碼
53
+ - **輕鬆測試**:單元測試無需外部服務依賴即可執行
54
+ - **簡化除錯**:快取行為在應用程式流程內可預測且可追蹤
55
+
14
56
  ## 安裝
15
57
 
16
58
  ```bash
@@ -77,6 +119,59 @@ await cache.put(`user:${userId}`, updatedUser, async (key, value) => {
77
119
  });
78
120
  ```
79
121
 
122
+ ### TTL(生存時間)支援
123
+
124
+ AsyncLRUCache 支援使用 TTL(Time To Live)自動過期快取項目:
125
+
126
+ ```typescript
127
+ import { AsyncLRUCache } from '@wfp99/async-lru-cache';
128
+
129
+ // 建立支援 TTL 的快取
130
+ const cache = new AsyncLRUCache({
131
+ capacity: 100,
132
+ defaultTtlMs: 5000, // 預設 TTL 為 5 秒
133
+ cleanupIntervalMs: 10000 // 每 10 秒清理過期項目
134
+ });
135
+
136
+ // 使用預設 TTL
137
+ const data1 = await cache.get('key1', async () => {
138
+ return await fetchData();
139
+ });
140
+
141
+ // 為特定項目覆寫 TTL
142
+ const data2 = await cache.get('key2', async () => {
143
+ return await fetchCriticalData();
144
+ }, 30000); // 30 秒 TTL
145
+
146
+ // 使用自訂 TTL 進行 Put 操作
147
+ await cache.put('key3', value, async (key, val) => {
148
+ await saveToDb(key, val);
149
+ }, 60000); // 1 分鐘 TTL
150
+
151
+ // 手動清理過期項目
152
+ cache.cleanupExpired();
153
+
154
+ // 檢查 key 是否存在且未過期
155
+ if (cache.has('key1')) {
156
+ console.log('Key 存在且有效');
157
+ }
158
+
159
+ // 取得快取大小
160
+ console.log('目前快取大小:', cache.size());
161
+
162
+ // 銷毀快取(停止清理計時器並清除所有資料)
163
+ cache.destroy();
164
+ ```
165
+
166
+ #### TTL 配置選項
167
+
168
+ - **`defaultTtlMs`**:所有快取項目的預設 TTL(可選)
169
+ - **`cleanupIntervalMs`**:過期項目的自動清理間隔(可選)
170
+ - 個別的 `get()` 和 `put()` 方法接受 TTL 覆寫
171
+ - 過期項目在正常操作期間會自動移除
172
+ - 呼叫 `cleanupExpired()` 進行手動清理
173
+ - 呼叫 `destroy()` 停止計時器並防止記憶體洩漏
174
+
80
175
  ### 快取管理
81
176
 
82
177
  ```typescript
package/dist/index.d.ts CHANGED
@@ -14,6 +14,18 @@ export interface AsyncLRUCacheOption {
14
14
  * Must not be less than 10.
15
15
  */
16
16
  capacity: number;
17
+ /**
18
+ * Default time to live for cache entries in milliseconds.
19
+ * If not specified, entries will not expire automatically.
20
+ * Individual entries can override this value.
21
+ */
22
+ defaultTtlMs?: number;
23
+ /**
24
+ * Interval in milliseconds for automatic cleanup of expired entries.
25
+ * If not specified, cleanup will only happen during normal operations.
26
+ * Setting this enables periodic background cleanup.
27
+ */
28
+ cleanupIntervalMs?: number;
17
29
  }
18
30
  /**
19
31
  * Asynchronous LRU Cache class.
@@ -21,12 +33,17 @@ export interface AsyncLRUCacheOption {
21
33
  * - Supports asynchronous savers for data persistence.
22
34
  * - Automatically merges concurrent requests (get) and serializes writes (put).
23
35
  * - Implements LRU eviction strategy.
36
+ * - Supports TTL (Time To Live) for automatic expiration of entries.
24
37
  */
25
38
  export declare class AsyncLRUCache<K, V> {
26
39
  /**
27
40
  * Maximum capacity of the cache.
28
41
  */
29
42
  private readonly capacity;
43
+ /**
44
+ * Default TTL for cache entries in milliseconds.
45
+ */
46
+ private readonly defaultTtlMs?;
30
47
  /**
31
48
  * Map for storing cache entries. The key is the cache key, and the value is the Node.
32
49
  */
@@ -39,12 +56,28 @@ export declare class AsyncLRUCache<K, V> {
39
56
  * Tail node of the linked list, pointing to the least recently used item.
40
57
  */
41
58
  private tail;
59
+ /**
60
+ * Timer ID for periodic cleanup of expired entries.
61
+ */
62
+ private cleanupTimer?;
42
63
  /**
43
64
  * Creates an instance of AsyncLRUCache with the specified options.
44
65
  * @param option - The configuration options for the cache.
45
66
  * @throws {Error} Throws an error if the provided capacity is less than 10.
46
67
  */
47
68
  constructor(option: AsyncLRUCacheOption);
69
+ /**
70
+ * Cleans up expired entries from the cache.
71
+ * This method removes all nodes that have exceeded their TTL.
72
+ */
73
+ private _cleanupExpired;
74
+ /**
75
+ * Checks if a node is expired and removes it if so.
76
+ * @param key - The key to check.
77
+ * @param node - The node to check.
78
+ * @returns True if the node was expired and removed, false otherwise.
79
+ */
80
+ private _checkAndRemoveExpired;
48
81
  /**
49
82
  * Checks if eviction is needed according to the cache strategy.
50
83
  * When the cache exceeds its capacity, automatically removes the tail (least recently used) node.
@@ -72,18 +105,20 @@ export declare class AsyncLRUCache<K, V> {
72
105
  * Automatically merges concurrent requests for the same key.
73
106
  * @param key - Cache key.
74
107
  * @param loader - Asynchronous loader function to execute on cache miss.
108
+ * @param ttlMs - Optional TTL override for this entry in milliseconds.
75
109
  * @returns A Promise that resolves to the required data.
76
110
  */
77
- get(key: K, loader: () => Promise<V>): Promise<V>;
111
+ get(key: K, loader: () => Promise<V>, ttlMs?: number): Promise<V>;
78
112
  /**
79
113
  * Puts a value into the cache, and optionally executes a saver function to persist it.
80
114
  * This method serializes multiple put operations for the same key, ensuring they execute in order.
81
115
  * @param key - Cache key.
82
116
  * @param value - Value to cache.
83
117
  * @param saver - Optional asynchronous save function.
118
+ * @param ttlMs - Optional TTL override for this entry in milliseconds.
84
119
  * @returns A Promise that resolves to the latest value after the saver operation completes.
85
120
  */
86
- put(key: K, value: V, saver?: (key: K, value: V) => Promise<void>): Promise<V>;
121
+ put(key: K, value: V, saver?: (key: K, value: V) => Promise<void>, ttlMs?: number): Promise<V>;
87
122
  /**
88
123
  * Invalidates and removes the cache entry associated with the specified key.
89
124
  * @param key - The key of the cache entry to invalidate.
@@ -93,4 +128,25 @@ export declare class AsyncLRUCache<K, V> {
93
128
  * Clears the entire cache, removing all entries.
94
129
  */
95
130
  clear(): void;
131
+ /**
132
+ * Destroys the cache instance, clearing all data and stopping any background timers.
133
+ * Call this method when you no longer need the cache to prevent memory leaks.
134
+ */
135
+ destroy(): void;
136
+ /**
137
+ * Manually triggers cleanup of expired entries.
138
+ * This is useful if you want to force cleanup without waiting for the automatic interval.
139
+ */
140
+ cleanupExpired(): void;
141
+ /**
142
+ * Gets the current number of entries in the cache.
143
+ * @returns The number of entries currently in the cache.
144
+ */
145
+ size(): number;
146
+ /**
147
+ * Checks if a key exists in the cache and is not expired.
148
+ * @param key - The key to check.
149
+ * @returns True if the key exists and is not expired, false otherwise.
150
+ */
151
+ has(key: K): boolean;
96
152
  }
package/dist/index.js CHANGED
@@ -16,8 +16,9 @@ class Node {
16
16
  * Creates a new Node instance.
17
17
  * @param key - The key associated with this node.
18
18
  * @param value - A Promise that resolves to the value of this node.
19
+ * @param ttlMs - Time to live in milliseconds. If provided, sets the expiration time.
19
20
  */
20
- constructor(key, value) {
21
+ constructor(key, value, ttlMs) {
21
22
  /**
22
23
  * Reference to the next node in the linked list.
23
24
  * This property is `null` if there is no next node.
@@ -28,8 +29,23 @@ class Node {
28
29
  * This property is `null` if there is no previous node.
29
30
  */
30
31
  this.prev = null;
32
+ /**
33
+ * The timestamp when this node expires (in milliseconds).
34
+ * If null, the node never expires.
35
+ */
36
+ this.expiresAt = null;
31
37
  this.key = key;
32
38
  this.value = value;
39
+ if (ttlMs !== undefined && ttlMs > 0) {
40
+ this.expiresAt = Date.now() + ttlMs;
41
+ }
42
+ }
43
+ /**
44
+ * Checks if this node has expired.
45
+ * @returns True if the node has expired, false otherwise.
46
+ */
47
+ isExpired() {
48
+ return this.expiresAt !== null && Date.now() > this.expiresAt;
33
49
  }
34
50
  }
35
51
  /**
@@ -38,6 +54,7 @@ class Node {
38
54
  * - Supports asynchronous savers for data persistence.
39
55
  * - Automatically merges concurrent requests (get) and serializes writes (put).
40
56
  * - Implements LRU eviction strategy.
57
+ * - Supports TTL (Time To Live) for automatic expiration of entries.
41
58
  */
42
59
  class AsyncLRUCache {
43
60
  /**
@@ -61,6 +78,48 @@ class AsyncLRUCache {
61
78
  if (option.capacity < 10)
62
79
  throw new Error("Capacity must be at least 10.");
63
80
  this.capacity = option.capacity;
81
+ this.defaultTtlMs = option.defaultTtlMs;
82
+ // Setup periodic cleanup if specified
83
+ if (option.cleanupIntervalMs && option.cleanupIntervalMs > 0) {
84
+ this.cleanupTimer = setInterval(() => {
85
+ this._cleanupExpired();
86
+ }, option.cleanupIntervalMs);
87
+ }
88
+ }
89
+ /**
90
+ * Cleans up expired entries from the cache.
91
+ * This method removes all nodes that have exceeded their TTL.
92
+ */
93
+ _cleanupExpired() {
94
+ const expiredKeys = [];
95
+ // Collect expired keys
96
+ for (const [key, node] of this.dataMap) {
97
+ if (node.isExpired()) {
98
+ expiredKeys.push(key);
99
+ }
100
+ }
101
+ // Remove expired entries
102
+ for (const key of expiredKeys) {
103
+ const node = this.dataMap.get(key);
104
+ if (node) {
105
+ this.dataMap.delete(key);
106
+ this._removeNode(node);
107
+ }
108
+ }
109
+ }
110
+ /**
111
+ * Checks if a node is expired and removes it if so.
112
+ * @param key - The key to check.
113
+ * @param node - The node to check.
114
+ * @returns True if the node was expired and removed, false otherwise.
115
+ */
116
+ _checkAndRemoveExpired(key, node) {
117
+ if (node.isExpired()) {
118
+ this.dataMap.delete(key);
119
+ this._removeNode(node);
120
+ return true;
121
+ }
122
+ return false;
64
123
  }
65
124
  /**
66
125
  * Checks if eviction is needed according to the cache strategy.
@@ -116,16 +175,24 @@ class AsyncLRUCache {
116
175
  * Automatically merges concurrent requests for the same key.
117
176
  * @param key - Cache key.
118
177
  * @param loader - Asynchronous loader function to execute on cache miss.
178
+ * @param ttlMs - Optional TTL override for this entry in milliseconds.
119
179
  * @returns A Promise that resolves to the required data.
120
180
  */
121
- get(key, loader) {
181
+ get(key, loader, ttlMs) {
122
182
  const node = this.dataMap.get(key);
123
183
  if (node) {
124
- this._moveToHead(node);
125
- return node.value;
184
+ // Check if the node has expired
185
+ if (this._checkAndRemoveExpired(key, node)) {
186
+ // Node was expired and removed, proceed to load fresh data
187
+ }
188
+ else {
189
+ this._moveToHead(node);
190
+ return node.value;
191
+ }
126
192
  }
127
193
  const loadingPromise = loader();
128
- const newNode = new Node(key, loadingPromise);
194
+ const effectiveTtlMs = ttlMs !== null && ttlMs !== void 0 ? ttlMs : this.defaultTtlMs;
195
+ const newNode = new Node(key, loadingPromise, effectiveTtlMs);
129
196
  this.dataMap.set(key, newNode);
130
197
  this._addToHead(newNode);
131
198
  this._evictIfNeeded();
@@ -144,9 +211,10 @@ class AsyncLRUCache {
144
211
  * @param key - Cache key.
145
212
  * @param value - Value to cache.
146
213
  * @param saver - Optional asynchronous save function.
214
+ * @param ttlMs - Optional TTL override for this entry in milliseconds.
147
215
  * @returns A Promise that resolves to the latest value after the saver operation completes.
148
216
  */
149
- put(key, value, saver) {
217
+ put(key, value, saver, ttlMs) {
150
218
  const lastPromise = this.dataMap.has(key) ? this.dataMap.get(key).value : Promise.resolve(undefined);
151
219
  const saverPromise = lastPromise.catch((err) => {
152
220
  // Ignore previous operation errors, so the new operation can proceed.
@@ -162,14 +230,22 @@ class AsyncLRUCache {
162
230
  return value;
163
231
  });
164
232
  let node = this.dataMap.get(key);
233
+ const effectiveTtlMs = ttlMs !== null && ttlMs !== void 0 ? ttlMs : this.defaultTtlMs;
165
234
  if (!node) {
166
- node = new Node(key, saverPromise);
235
+ node = new Node(key, saverPromise, effectiveTtlMs);
167
236
  this.dataMap.set(key, node);
168
237
  this._addToHead(node);
169
238
  this._evictIfNeeded();
170
239
  }
171
240
  else {
241
+ // Update existing node with new value and TTL
172
242
  node.value = saverPromise;
243
+ if (effectiveTtlMs !== undefined && effectiveTtlMs > 0) {
244
+ node.expiresAt = Date.now() + effectiveTtlMs;
245
+ }
246
+ else {
247
+ node.expiresAt = null;
248
+ }
173
249
  this._moveToHead(node);
174
250
  }
175
251
  saverPromise.catch(err => {
@@ -208,11 +284,54 @@ class AsyncLRUCache {
208
284
  node.next = null;
209
285
  node.key = null;
210
286
  node.value = Promise.resolve(undefined);
287
+ node.expiresAt = null;
211
288
  // Move to the next node.
212
289
  node = next;
213
290
  }
214
291
  this.head = null;
215
292
  this.tail = null;
216
293
  }
294
+ /**
295
+ * Destroys the cache instance, clearing all data and stopping any background timers.
296
+ * Call this method when you no longer need the cache to prevent memory leaks.
297
+ */
298
+ destroy() {
299
+ // Stop the cleanup timer if it exists
300
+ if (this.cleanupTimer) {
301
+ clearInterval(this.cleanupTimer);
302
+ this.cleanupTimer = undefined;
303
+ }
304
+ // Clear all cache data
305
+ this.clear();
306
+ }
307
+ /**
308
+ * Manually triggers cleanup of expired entries.
309
+ * This is useful if you want to force cleanup without waiting for the automatic interval.
310
+ */
311
+ cleanupExpired() {
312
+ this._cleanupExpired();
313
+ }
314
+ /**
315
+ * Gets the current number of entries in the cache.
316
+ * @returns The number of entries currently in the cache.
317
+ */
318
+ size() {
319
+ return this.dataMap.size;
320
+ }
321
+ /**
322
+ * Checks if a key exists in the cache and is not expired.
323
+ * @param key - The key to check.
324
+ * @returns True if the key exists and is not expired, false otherwise.
325
+ */
326
+ has(key) {
327
+ const node = this.dataMap.get(key);
328
+ if (!node) {
329
+ return false;
330
+ }
331
+ if (this._checkAndRemoveExpired(key, node)) {
332
+ return false;
333
+ }
334
+ return true;
335
+ }
217
336
  }
218
337
  exports.AsyncLRUCache = AsyncLRUCache;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wfp99/async-lru-cache",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "A simple memory cache using the LRU algorithm and supporting asynchronous data access.",
5
5
  "keywords": [
6
6
  "cache",