@wfp99/async-lru-cache 1.1.0 โ 1.2.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 +78 -229
- package/README.zh-TW.md +80 -228
- package/dist/index.d.ts +70 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -14
- package/dist/index.js.map +1 -0
- package/package.json +13 -4
package/README.md
CHANGED
|
@@ -4,58 +4,17 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
|
|
7
|
-
An
|
|
7
|
+
An in-memory LRU (Least Recently Used) cache for Node.js and TypeScript, with support for asynchronous loading, saving, and automatic deduplication of concurrent requests.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
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
|
|
11
|
+
- Asynchronous loader (`get`) and saver (`put`) functions
|
|
12
|
+
- Concurrent `get()` calls for the same key share a single loader execution
|
|
13
|
+
- `put()` calls for the same key are serialized and execute in order
|
|
14
|
+
- LRU eviction once the configured capacity is exceeded
|
|
15
|
+
- Optional per-entry TTL (time to live), with optional periodic background cleanup
|
|
16
|
+
- Configurable error handling via `onError`, defaulting to console logging
|
|
17
|
+
- `get()` can be called without a loader for a read-only lookup, and `peek()` for a lookup that never affects LRU order
|
|
59
18
|
|
|
60
19
|
## Installation
|
|
61
20
|
|
|
@@ -69,229 +28,122 @@ npm install @wfp99/async-lru-cache
|
|
|
69
28
|
|
|
70
29
|
## Usage
|
|
71
30
|
|
|
72
|
-
### Basic
|
|
31
|
+
### Basic usage
|
|
73
32
|
|
|
74
33
|
```typescript
|
|
75
34
|
import { AsyncLRUCache } from '@wfp99/async-lru-cache';
|
|
76
35
|
|
|
77
|
-
|
|
78
|
-
const cache = new AsyncLRUCache({
|
|
79
|
-
capacity: 100
|
|
80
|
-
});
|
|
36
|
+
const cache = new AsyncLRUCache<string, User>({ capacity: 100 });
|
|
81
37
|
|
|
82
|
-
//
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return response.json();
|
|
38
|
+
// get() calls the loader on a cache miss and caches the resolved value.
|
|
39
|
+
const user = await cache.get('user:123', async () => {
|
|
40
|
+
const response = await fetch('/api/users/123');
|
|
41
|
+
return response.json();
|
|
87
42
|
});
|
|
88
43
|
|
|
89
|
-
//
|
|
44
|
+
// put() stores a value directly and optionally persists it via a saver.
|
|
90
45
|
await cache.put('user:456', userData, async (key, value) => {
|
|
91
|
-
|
|
92
|
-
await saveToDatabase(key, value);
|
|
46
|
+
await saveToDatabase(key, value);
|
|
93
47
|
});
|
|
94
48
|
```
|
|
95
49
|
|
|
96
|
-
###
|
|
50
|
+
### Read-only lookups
|
|
97
51
|
|
|
98
52
|
```typescript
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error('Cache load failed:', error);
|
|
105
|
-
// Failed items are automatically removed from cache
|
|
106
|
-
}
|
|
107
|
-
```
|
|
53
|
+
// get() without a loader performs a read-only lookup: on a hit it behaves like a
|
|
54
|
+
// normal get() (and updates LRU order); on a miss it resolves to undefined without
|
|
55
|
+
// adding anything to the cache or affecting LRU order.
|
|
56
|
+
const cached = await cache.get('user:123'); // User | undefined
|
|
108
57
|
|
|
109
|
-
|
|
58
|
+
// peek() never affects LRU order, whether it is a hit or a miss.
|
|
59
|
+
const peeked = await cache.peek('user:123'); // Promise<User> | undefined
|
|
60
|
+
```
|
|
110
61
|
|
|
111
|
-
|
|
62
|
+
### TTL (time to live)
|
|
112
63
|
|
|
113
64
|
```typescript
|
|
114
|
-
import { AsyncLRUCache } from '@wfp99/async-lru-cache';
|
|
115
|
-
|
|
116
|
-
// Create cache with TTL support
|
|
117
65
|
const cache = new AsyncLRUCache({
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// Use default TTL
|
|
124
|
-
const data1 = await cache.get('key1', async () => {
|
|
125
|
-
return await fetchData();
|
|
66
|
+
capacity: 100,
|
|
67
|
+
defaultTtlMs: 5000, // default TTL applied to every entry
|
|
68
|
+
cleanupIntervalMs: 10000, // periodic background cleanup of expired entries
|
|
126
69
|
});
|
|
127
70
|
|
|
128
|
-
// Override TTL for specific
|
|
129
|
-
|
|
130
|
-
return await fetchCriticalData();
|
|
131
|
-
}, 30000); // 30 seconds TTL
|
|
71
|
+
// Override the default TTL for a specific entry.
|
|
72
|
+
await cache.get('key1', async () => fetchData(), 30000);
|
|
132
73
|
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
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();
|
|
74
|
+
cache.has('key1'); // false once the entry has expired
|
|
75
|
+
cache.cleanupExpired(); // manually remove expired entries
|
|
76
|
+
cache.destroy(); // stop the cleanup timer and clear all data
|
|
151
77
|
```
|
|
152
78
|
|
|
153
|
-
|
|
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
|
-
|
|
162
|
-
### Advanced Usage
|
|
79
|
+
### Concurrency handling
|
|
163
80
|
|
|
164
81
|
```typescript
|
|
165
|
-
//
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
});
|
|
82
|
+
// These concurrent get() calls share a single loader execution.
|
|
83
|
+
const [a, b, c] = await Promise.all([
|
|
84
|
+
cache.get('shared-key', loader),
|
|
85
|
+
cache.get('shared-key', loader),
|
|
86
|
+
cache.get('shared-key', loader),
|
|
87
|
+
]);
|
|
172
88
|
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
89
|
+
// These put() calls execute sequentially, even though they are started concurrently.
|
|
90
|
+
cache.put('key', 'value1', saver1);
|
|
91
|
+
cache.put('key', 'value2', saver2);
|
|
92
|
+
cache.put('key', 'value3', saver3);
|
|
177
93
|
```
|
|
178
94
|
|
|
179
|
-
###
|
|
95
|
+
### Error handling
|
|
180
96
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
97
|
+
- If a loader (`get`) throws, the entry is removed from the cache and the rejection propagates to the caller.
|
|
98
|
+
- If a saver (`put`) throws, the entry is also removed to avoid caching an unpersisted value.
|
|
99
|
+
- A `put()` call ignores the failure of a previous, already-settled operation on the same key, so it can still proceed.
|
|
100
|
+
- By default, these failures are logged with `console.error`/`console.warn`. Provide `onError` to handle them yourself instead:
|
|
184
101
|
|
|
185
|
-
|
|
186
|
-
cache
|
|
102
|
+
```typescript
|
|
103
|
+
const cache = new AsyncLRUCache({
|
|
104
|
+
capacity: 100,
|
|
105
|
+
onError(error, { key, source }) {
|
|
106
|
+
// source is 'loader' | 'saver' | 'put-chain'
|
|
107
|
+
myLogger.error(`cache ${source} failed for ${key}`, error);
|
|
108
|
+
},
|
|
109
|
+
});
|
|
187
110
|
```
|
|
188
111
|
|
|
189
112
|
## API Reference
|
|
190
113
|
|
|
191
114
|
### `AsyncLRUCache<K, V>`
|
|
192
115
|
|
|
193
|
-
#### Constructor
|
|
194
|
-
|
|
195
116
|
```typescript
|
|
196
|
-
constructor(option: AsyncLRUCacheOption)
|
|
117
|
+
constructor(option: AsyncLRUCacheOption<K>)
|
|
197
118
|
```
|
|
198
119
|
|
|
199
|
-
#### `AsyncLRUCacheOption
|
|
120
|
+
#### `AsyncLRUCacheOption<K>`
|
|
200
121
|
|
|
201
122
|
| Property | Type | Required | Description |
|
|
202
|
-
|
|
203
|
-
| `capacity` | `number` | Yes | Maximum number of items allowed in cache. Must be
|
|
123
|
+
|---|---|---|---|
|
|
124
|
+
| `capacity` | `number` | Yes | Maximum number of items allowed in the cache. Must be at least 10. |
|
|
125
|
+
| `defaultTtlMs` | `number` | No | Default TTL applied to entries that don't specify their own. |
|
|
126
|
+
| `cleanupIntervalMs` | `number` | No | Interval for automatic background cleanup of expired entries. |
|
|
127
|
+
| `onError` | `(error: unknown, context: { key: K; source: 'loader' \| 'saver' \| 'put-chain' }) => void` | No | Callback for loader/saver failures. Replaces the default console logging when provided. |
|
|
204
128
|
|
|
205
129
|
#### Methods
|
|
206
130
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
- **key**: Cache key
|
|
220
|
-
- **value**: Value to cache
|
|
221
|
-
- **saver**: Optional asynchronous saver function
|
|
222
|
-
- **Returns**: Promise that resolves to the latest value after saver operation completes
|
|
223
|
-
|
|
224
|
-
##### `invalidate(key: K): void`
|
|
131
|
+
| Method | Description |
|
|
132
|
+
|---|---|
|
|
133
|
+
| `get(key, loader, ttlMs?)` | Returns the cached value, or calls `loader()` on a miss and caches the result. |
|
|
134
|
+
| `get(key)` | Read-only lookup without a loader. On a hit, behaves like the overload above (updates LRU order). On a miss, resolves to `undefined` without touching the cache. |
|
|
135
|
+
| `peek(key)` | Returns the cached value's `Promise<V>`, or `undefined` if missing/expired. Never affects LRU order, even on a hit. |
|
|
136
|
+
| `put(key, value, saver?, ttlMs?)` | Stores `value` and optionally awaits `saver(key, value)` to persist it. |
|
|
137
|
+
| `invalidate(key)` | Removes the entry for `key`, if present. |
|
|
138
|
+
| `clear()` | Removes all entries. |
|
|
139
|
+
| `has(key)` | Returns whether `key` exists and has not expired. Expired entries are evicted as a side effect of this check; it does not affect LRU order. |
|
|
140
|
+
| `size()` | Returns the current number of entries. |
|
|
141
|
+
| `cleanupExpired()` | Immediately removes all expired entries. |
|
|
142
|
+
| `destroy()` | Stops the cleanup timer (if any) and clears all data. |
|
|
225
143
|
|
|
226
|
-
|
|
144
|
+
## TypeScript
|
|
227
145
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
##### `clear(): void`
|
|
231
|
-
|
|
232
|
-
Clears all cache entries. This method removes all items from cache and manually clears node links to prevent potential memory leaks.
|
|
233
|
-
|
|
234
|
-
## Concurrency Handling
|
|
235
|
-
|
|
236
|
-
### GET Request Merging
|
|
237
|
-
|
|
238
|
-
When multiple concurrent requests fetch the same key, AsyncLRUCache automatically merges these requests, ensuring the loader function executes only once:
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
// These three concurrent requests will share the same loader execution
|
|
242
|
-
const [data1, data2, data3] = await Promise.all([
|
|
243
|
-
cache.get('shared-key', loader),
|
|
244
|
-
cache.get('shared-key', loader),
|
|
245
|
-
cache.get('shared-key', loader)
|
|
246
|
-
]);
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### PUT Operation Serialization
|
|
250
|
-
|
|
251
|
-
Multiple PUT operations for the same key are serialized to ensure they execute in order:
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
// These operations will execute sequentially, even if started concurrently
|
|
255
|
-
cache.put('key', 'value1', saver1);
|
|
256
|
-
cache.put('key', 'value2', saver2);
|
|
257
|
-
cache.put('key', 'value3', saver3);
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
## TypeScript Support
|
|
261
|
-
|
|
262
|
-
This package is fully written in TypeScript and provides complete type support:
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
interface User {
|
|
266
|
-
id: string;
|
|
267
|
-
name: string;
|
|
268
|
-
email: string;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const userCache = new AsyncLRUCache<string, User>({
|
|
272
|
-
capacity: 1000
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
const user: User = await userCache.get('user:123', async () => {
|
|
276
|
-
// Loader must return User type
|
|
277
|
-
return fetchUserFromAPI('123');
|
|
278
|
-
});
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
## Error Handling
|
|
282
|
-
|
|
283
|
-
- **Loader Failures**: If loader function throws an exception, corresponding cache entry is automatically removed
|
|
284
|
-
- **Saver Failures**: If saver function fails, cache entry is also removed to ensure data consistency
|
|
285
|
-
- **Operation Chain Errors**: PUT operations ignore previous operation errors, allowing new operations to proceed
|
|
286
|
-
- **Error Logging**: All errors are automatically logged to console for debugging
|
|
287
|
-
|
|
288
|
-
## Memory Management
|
|
289
|
-
|
|
290
|
-
AsyncLRUCache provides comprehensive memory management:
|
|
291
|
-
|
|
292
|
-
- **Automatic Eviction**: Automatically removes least recently used items based on capacity
|
|
293
|
-
- **Manual Cleanup**: `clear()` method thoroughly cleans all node links to prevent memory leaks
|
|
294
|
-
- **Error Cleanup**: Automatically cleans related cache entries when operations fail
|
|
146
|
+
This package is written in TypeScript and ships with type declarations; no separate `@types` package is required.
|
|
295
147
|
|
|
296
148
|
## License
|
|
297
149
|
|
|
@@ -301,6 +153,3 @@ MIT
|
|
|
301
153
|
|
|
302
154
|
Issues and pull requests are welcome on [GitHub](https://github.com/wfp99/async-lru-cache).
|
|
303
155
|
|
|
304
|
-
## Author
|
|
305
|
-
|
|
306
|
-
Wang Feng Ping
|
package/README.zh-TW.md
CHANGED
|
@@ -1,57 +1,20 @@
|
|
|
1
1
|
# Async LRU Cache
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://badge.fury.io/js/@wfp99%2Fasync-lru-cache)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
|
|
7
|
+
ไธๅๆฏๆด้ๅๆญฅ่ผๅ
ฅ่ไฟๅญๆไฝใไธฆ่ชๅ่็ไธฆ็ผ่ซๆฑ็ LRU๏ผLeast Recently Used๏ผ่จๆถ้ซๅฟซๅ๏ผ้ฉ็จๆผ Node.js ่ TypeScriptใ
|
|
4
8
|
|
|
5
9
|
## ็น่ฒ
|
|
6
10
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
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
|
-
- **็ฐกๅ้ค้ฏ**๏ผๅฟซๅ่ก็บๅจๆ็จ็จๅผๆต็จๅ
งๅฏ้ ๆธฌไธๅฏ่ฟฝ่นค
|
|
11
|
+
- ๆฏๆด้ๅๆญฅ็่ผๅ
ฅๅจ๏ผloader๏ผ่ไฟๅญๅจ๏ผsaver๏ผๅฝๆธ
|
|
12
|
+
- ๅฐๅไธ key ็ไธฆ็ผ `get()` ๅผๅซๅ
ฑ็จๅฎไธ่ผๅ
ฅๅจๅท่ก
|
|
13
|
+
- ๅฐๅไธ key ็ๅคๅ `put()` ๅผๅซๆๅบๅๅไธฆไพๅบๅท่ก
|
|
14
|
+
- ่ถ
ๅบ่จญๅฎๅฎน้ๆ่ชๅๅท่ก LRU ๆทๆฑฐ
|
|
15
|
+
- ๆฏๆดๆฏ็ญ้
็ฎ็ๅฏ้ธ TTL๏ผๅญๆดปๆ้๏ผ๏ผไธฆๅฏ่จญๅฎ้ฑๆๆง่ๆฏๆธ
็
|
|
16
|
+
- ๅฏ้้ `onError` ่ช่จ้ฏ่ชค่็๏ผ้ ่จญ็บ่จ้ๅฐ console
|
|
17
|
+
- `get()` ๅฏ็็ฅ loader ้ฒ่กๅฏ่ฎๆฅ่ฉข๏ผ`peek()` ๅๆไพๅฎๅ
จไธๅฝฑ้ฟ LRU ้ ๅบ็ๆฅ่ฉขๆนๅผ
|
|
55
18
|
|
|
56
19
|
## ๅฎ่ฃ
|
|
57
20
|
|
|
@@ -70,224 +33,116 @@ npm install @wfp99/async-lru-cache
|
|
|
70
33
|
```typescript
|
|
71
34
|
import { AsyncLRUCache } from '@wfp99/async-lru-cache';
|
|
72
35
|
|
|
73
|
-
|
|
74
|
-
const cache = new AsyncLRUCache({
|
|
75
|
-
capacity: 100
|
|
76
|
-
});
|
|
36
|
+
const cache = new AsyncLRUCache<string, User>({ capacity: 100 });
|
|
77
37
|
|
|
78
|
-
//
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return response.json();
|
|
38
|
+
// get() ๅจๅฟซๅๆชๅฝไธญๆๅผๅซ loader๏ผไธฆๅฟซๅๅ
ถๅๅณๅผใ
|
|
39
|
+
const user = await cache.get('user:123', async () => {
|
|
40
|
+
const response = await fetch('/api/users/123');
|
|
41
|
+
return response.json();
|
|
83
42
|
});
|
|
84
43
|
|
|
85
|
-
//
|
|
44
|
+
// put() ็ดๆฅๅฒๅญๅผ๏ผไธฆๅฏ้ธๆ้้ saver ้ฒ่กๆไน
ๅใ
|
|
86
45
|
await cache.put('user:456', userData, async (key, value) => {
|
|
87
|
-
|
|
88
|
-
await saveToDatabase(key, value);
|
|
46
|
+
await saveToDatabase(key, value);
|
|
89
47
|
});
|
|
90
48
|
```
|
|
91
49
|
|
|
92
|
-
###
|
|
50
|
+
### ๅฏ่ฎๆฅ่ฉข
|
|
93
51
|
|
|
94
52
|
```typescript
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
});
|
|
99
|
-
} catch (error) {
|
|
100
|
-
console.error('ๅฟซๅ่ผๅ
ฅๅคฑๆ:', error);
|
|
101
|
-
// ๅคฑๆ็้
็ฎๆ่ชๅๅพๅฟซๅไธญ็งป้ค
|
|
102
|
-
}
|
|
103
|
-
```
|
|
53
|
+
// ็็ฅ loader ็ get() ๅฑฌๆผๅฏ่ฎๆฅ่ฉข๏ผๅฝไธญๆ่ก็บ่ไธ่ฌ get() ็ธๅ๏ผๆๆดๆฐ LRU ้ ๅบ๏ผ๏ผ
|
|
54
|
+
// ๆชๅฝไธญๆๅๅณ undefined๏ผไธไธๆๆฐๅขไปปไฝ้
็ฎๆๅฝฑ้ฟ LRU ้ ๅบใ
|
|
55
|
+
const cached = await cache.get('user:123'); // User | undefined
|
|
104
56
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
// ่่ณๆๅบซ้
ๅไฝฟ็จ
|
|
109
|
-
const cache = new AsyncLRUCache<string, UserData>({ capacity: 500 });
|
|
110
|
-
|
|
111
|
-
// ๅพ่ณๆๅบซ่ผๅ
ฅไธฆ่ชๅๅฟซๅ
|
|
112
|
-
const user = await cache.get(`user:${userId}`, async () => {
|
|
113
|
-
return await database.users.findById(userId);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
// ๅๆๅฒๅญๅฐๅฟซๅๅ่ณๆๅบซ
|
|
117
|
-
await cache.put(`user:${userId}`, updatedUser, async (key, value) => {
|
|
118
|
-
await database.users.update(userId, value);
|
|
119
|
-
});
|
|
57
|
+
// peek() ็ก่ซๅฝไธญๆๆชๅฝไธญ้ฝไธๆๅฝฑ้ฟ LRU ้ ๅบใ
|
|
58
|
+
const peeked = await cache.peek('user:123'); // Promise<User> | undefined
|
|
120
59
|
```
|
|
121
60
|
|
|
122
|
-
### TTL
|
|
123
|
-
|
|
124
|
-
AsyncLRUCache ๆฏๆดไฝฟ็จ TTL๏ผTime To Live๏ผ่ชๅ้ๆๅฟซๅ้
็ฎ๏ผ
|
|
61
|
+
### TTL๏ผๅญๆดปๆ้๏ผ
|
|
125
62
|
|
|
126
63
|
```typescript
|
|
127
|
-
import { AsyncLRUCache } from '@wfp99/async-lru-cache';
|
|
128
|
-
|
|
129
|
-
// ๅปบ็ซๆฏๆด TTL ็ๅฟซๅ
|
|
130
64
|
const cache = new AsyncLRUCache({
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// ไฝฟ็จ้ ่จญ TTL
|
|
137
|
-
const data1 = await cache.get('key1', async () => {
|
|
138
|
-
return await fetchData();
|
|
65
|
+
capacity: 100,
|
|
66
|
+
defaultTtlMs: 5000, // ๅฅ็จๅฐๆฏ็ญ้
็ฎ็้ ่จญ TTL
|
|
67
|
+
cleanupIntervalMs: 10000, // ้ฑๆๆง่ๆฏๆธ
็้ๆ้
็ฎ
|
|
139
68
|
});
|
|
140
69
|
|
|
141
|
-
//
|
|
142
|
-
|
|
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
|
|
70
|
+
// ็บ็นๅฎ้
็ฎ่ฆๅฏซ้ ่จญ TTLใ
|
|
71
|
+
await cache.get('key1', async () => fetchData(), 30000);
|
|
150
72
|
|
|
151
|
-
//
|
|
152
|
-
cache.cleanupExpired();
|
|
73
|
+
cache.has('key1'); // ้
็ฎ้ๆๅพๅๅณ false
|
|
74
|
+
cache.cleanupExpired(); // ๆๅ็งป้ค้ๆ้
็ฎ
|
|
75
|
+
cache.destroy(); // ๅๆญขๆธ
็่จๆๅจไธฆๆธ
้คๆๆ่ณๆ
|
|
76
|
+
```
|
|
153
77
|
|
|
154
|
-
|
|
155
|
-
if (cache.has('key1')) {
|
|
156
|
-
console.log('Key ๅญๅจไธๆๆ');
|
|
157
|
-
}
|
|
78
|
+
### ไธฆ็ผ่็
|
|
158
79
|
|
|
159
|
-
|
|
160
|
-
|
|
80
|
+
```typescript
|
|
81
|
+
// ไปฅไธไธฆ็ผ็ get() ๅผๅซๆๅ
ฑ็จๅไธๅ loader ๅท่กใ
|
|
82
|
+
const [a, b, c] = await Promise.all([
|
|
83
|
+
cache.get('shared-key', loader),
|
|
84
|
+
cache.get('shared-key', loader),
|
|
85
|
+
cache.get('shared-key', loader),
|
|
86
|
+
]);
|
|
161
87
|
|
|
162
|
-
//
|
|
163
|
-
cache.
|
|
88
|
+
// ไปฅไธ put() ๅผๅซๅณไฝฟไธฆ็ผๅๅ๏ผไนๆไพๅบๅบๅๅๅท่กใ
|
|
89
|
+
cache.put('key', 'value1', saver1);
|
|
90
|
+
cache.put('key', 'value2', saver2);
|
|
91
|
+
cache.put('key', 'value3', saver3);
|
|
164
92
|
```
|
|
165
93
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
- **`defaultTtlMs`**๏ผๆๆๅฟซๅ้
็ฎ็้ ่จญ TTL๏ผๅฏ้ธ๏ผ
|
|
169
|
-
- **`cleanupIntervalMs`**๏ผ้ๆ้
็ฎ็่ชๅๆธ
็้้๏ผๅฏ้ธ๏ผ
|
|
170
|
-
- ๅๅฅ็ `get()` ๅ `put()` ๆนๆณๆฅๅ TTL ่ฆๅฏซ
|
|
171
|
-
- ้ๆ้
็ฎๅจๆญฃๅธธๆไฝๆ้ๆ่ชๅ็งป้ค
|
|
172
|
-
- ๅผๅซ `cleanupExpired()` ้ฒ่กๆๅๆธ
็
|
|
173
|
-
- ๅผๅซ `destroy()` ๅๆญข่จๆๅจไธฆ้ฒๆญข่จๆถ้ซๆดฉๆผ
|
|
94
|
+
### ้ฏ่ชค่็
|
|
174
95
|
|
|
175
|
-
|
|
96
|
+
- ่ฅ่ผๅ
ฅๅจ๏ผ`get`๏ผๆๅบไพๅค๏ผ่ฉฒ้
็ฎๆๅพๅฟซๅไธญ็งป้ค๏ผ้ฏ่ชคๆๅณ้็ตฆๅผๅซ็ซฏใ
|
|
97
|
+
- ่ฅไฟๅญๅจ๏ผ`put`๏ผๆๅบไพๅค๏ผ่ฉฒ้
็ฎไนๆ่ขซ็งป้ค๏ผ้ฟๅ
ๅฟซๅๅฐๅฐๆชๆไน
ๅ็ๅผใ
|
|
98
|
+
- `put()` ๆๅฟฝ็ฅๅไธ key ๅไธๅๅทฒ็ตๆๆไฝ็ๅคฑๆ๏ผ่ฎๆฐ็ๆไฝๅฏไปฅ็นผ็บ้ฒ่กใ
|
|
99
|
+
- ้ ่จญๆ
ๆณไธ๏ผไธ่ฟฐๅคฑๆๆ้้ `console.error`/`console.warn` ่จ้ใ่ฅ่ฆ่ช่ก่็๏ผๅฏๆไพ `onError`๏ผ
|
|
176
100
|
|
|
177
101
|
```typescript
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
//
|
|
182
|
-
|
|
102
|
+
const cache = new AsyncLRUCache({
|
|
103
|
+
capacity: 100,
|
|
104
|
+
onError(error, { key, source }) {
|
|
105
|
+
// source ็บ 'loader' | 'saver' | 'put-chain'
|
|
106
|
+
myLogger.error(`cache ${source} failed for ${key}`, error);
|
|
107
|
+
},
|
|
108
|
+
});
|
|
183
109
|
```
|
|
184
110
|
|
|
185
111
|
## API ๅ่
|
|
186
112
|
|
|
187
113
|
### `AsyncLRUCache<K, V>`
|
|
188
114
|
|
|
189
|
-
#### ๅปบๆงๅฝๆธ
|
|
190
|
-
|
|
191
115
|
```typescript
|
|
192
|
-
constructor(option: AsyncLRUCacheOption)
|
|
116
|
+
constructor(option: AsyncLRUCacheOption<K>)
|
|
193
117
|
```
|
|
194
118
|
|
|
195
|
-
#### `AsyncLRUCacheOption
|
|
119
|
+
#### `AsyncLRUCacheOption<K>`
|
|
196
120
|
|
|
197
121
|
| ๅฑฌๆง | ้กๅ | ๅฟ
้ | ๆ่ฟฐ |
|
|
198
|
-
|
|
199
|
-
| `capacity` | `number` | ๆฏ |
|
|
122
|
+
|---|---|---|---|
|
|
123
|
+
| `capacity` | `number` | ๆฏ | ๅฟซๅไธญๅ
่จฑ็ๆๅคง้
็ฎๆธ้๏ผๆๅฐๅผ็บ 10 |
|
|
124
|
+
| `defaultTtlMs` | `number` | ๅฆ | ๅฅ็จๅฐๆชๆๅฎ TTL ไน้
็ฎ็้ ่จญ TTL |
|
|
125
|
+
| `cleanupIntervalMs` | `number` | ๅฆ | ่ชๅ่ๆฏๆธ
็้ๆ้
็ฎ็ๅท่ก้้ |
|
|
126
|
+
| `onError` | `(error: unknown, context: { key: K; source: 'loader' \| 'saver' \| 'put-chain' }) => void` | ๅฆ | ่ผๅ
ฅๅจ/ไฟๅญๅจๅคฑๆๆ็ๅๅผๅฝๆธใๆไพๅพๅฐๅไปฃ้ ่จญ็ console ่จ้่ก็บ |
|
|
200
127
|
|
|
201
128
|
#### ๆนๆณ
|
|
202
129
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
130
|
+
| ๆนๆณ | ๆ่ฟฐ |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `get(key, loader, ttlMs?)` | ๅๅณๅฟซๅๅผ๏ผๆชๅฝไธญๆๅผๅซ `loader()` ไธฆๅฟซๅๅ
ถ็ตๆ |
|
|
133
|
+
| `get(key)` | ็็ฅ loader ็ๅฏ่ฎๆฅ่ฉขใๅฝไธญๆ่ก็บ่ไธๆนๅค่ผ็ธๅ๏ผๆๆดๆฐ LRU ้ ๅบ๏ผ๏ผๆชๅฝไธญๆๅๅณ `undefined`๏ผไธๆ็ฐๅๅฟซๅ |
|
|
134
|
+
| `peek(key)` | ๅๅณๅฟซๅๅผ็ `Promise<V>`๏ผ่ฅไธๅญๅจๆๅทฒ้ๆๅๅๅณ `undefined`ใ็ก่ซๅฝไธญ่ๅฆ้ฝไธๅฝฑ้ฟ LRU ้ ๅบ |
|
|
135
|
+
| `put(key, value, saver?, ttlMs?)` | ๅฒๅญ `value`๏ผไธฆๅฏ้ธๆ็ญๅพ
`saver(key, value)` ้ฒ่กๆไน
ๅ |
|
|
136
|
+
| `invalidate(key)` | ่ฅๅญๅจ๏ผ็งป้ค `key` ๅฐๆ็้
็ฎ |
|
|
137
|
+
| `clear()` | ็งป้คๆๆ้
็ฎ |
|
|
138
|
+
| `has(key)` | ๅๅณ `key` ๆฏๅฆๅญๅจไธๆช้ๆใๆญคๆชขๆฅๆ้ ๅธถๆธ
้คๅทฒ้ๆ็้
็ฎ๏ผไฝไธๅฝฑ้ฟ LRU ้ ๅบ |
|
|
139
|
+
| `size()` | ๅๅณ็ฎๅ็้
็ฎๆธ้ |
|
|
140
|
+
| `cleanupExpired()` | ็ซๅณ็งป้คๆๆ้ๆ้
็ฎ |
|
|
141
|
+
| `destroy()` | ๅๆญขๆธ
็่จๆๅจ๏ผ่ฅๆ๏ผไธฆๆธ
้คๆๆ่ณๆ |
|
|
214
142
|
|
|
215
|
-
|
|
216
|
-
- **value**: ่ฆๅฟซๅ็ๅผ
|
|
217
|
-
- **saver**: ๅฏ้ธ็้ๅๆญฅไฟๅญๅฝๆธ
|
|
218
|
-
- **ๅๅณ**: Promise๏ผ่งฃๆ็บไฟๅญๆไฝๅฎๆๅพ็ๆๆฐๅผ
|
|
143
|
+
## TypeScript
|
|
219
144
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
ไฝฟๆๅฎ้ต็ๅฟซๅ้
็ฎๅคฑๆไธฆ็งป้คใ
|
|
223
|
-
|
|
224
|
-
- **key**: ่ฆๅคฑๆ็ๅฟซๅ้ต
|
|
225
|
-
|
|
226
|
-
##### `clear(): void`
|
|
227
|
-
|
|
228
|
-
ๆธ
้คๆๆๅฟซๅ้
็ฎใๆญคๆนๆณๆ็งป้คๅฟซๅไธญ็ๆๆ้
็ฎไธฆๆๅๆธ
็็ฏ้ป้ฃ็ตไปฅ้ฟๅ
ๆฝๅจ็่จๆถ้ซๆดฉๆผใ
|
|
229
|
-
|
|
230
|
-
## ไธฆ็ผ่็
|
|
231
|
-
|
|
232
|
-
### GET ่ซๆฑๅไฝต
|
|
233
|
-
|
|
234
|
-
็ถๅคๅไธฆ็ผ่ซๆฑ็ฒๅ็ธๅ็ key ๆ๏ผAsyncLRUCache ๆ่ชๅๅไฝต้ไบ่ซๆฑ๏ผ็ขบไฟ่ผๅ
ฅๅจๅฝๆธๅชๅท่กไธๆฌก๏ผ
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
// ้ไธๅไธฆ็ผ่ซๆฑๆๅ
ฑไบซๅไธๅ่ผๅ
ฅๅจๅท่ก
|
|
238
|
-
const [data1, data2, data3] = await Promise.all([
|
|
239
|
-
cache.get('shared-key', loader),
|
|
240
|
-
cache.get('shared-key', loader),
|
|
241
|
-
cache.get('shared-key', loader)
|
|
242
|
-
]);
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
### PUT ๆไฝๅบๅๅ
|
|
246
|
-
|
|
247
|
-
ๅฐๅไธ key ็ๅคๅ PUT ๆไฝๆ่ขซๅบๅๅ๏ผ็ขบไฟๅฎๅๆ้ ๅบๅท่ก๏ผ
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
// ้ไบๆไฝๆๆ้ ๅบๅท่ก๏ผๅณไฝฟๅฎๅๆฏไธฆ็ผๅๅ็
|
|
251
|
-
cache.put('key', 'value1', saver1);
|
|
252
|
-
cache.put('key', 'value2', saver2);
|
|
253
|
-
cache.put('key', 'value3', saver3);
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
## TypeScript ๆฏๆด
|
|
257
|
-
|
|
258
|
-
ๆญคๅฅไปถๅฎๅ
จไฝฟ็จ TypeScript ็ทจๅฏซ๏ผๆไพๅฎๆด็ๅๅฅๆฏๆด๏ผ
|
|
259
|
-
|
|
260
|
-
```typescript
|
|
261
|
-
interface User {
|
|
262
|
-
id: string;
|
|
263
|
-
name: string;
|
|
264
|
-
email: string;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const userCache = new AsyncLRUCache<string, User>({
|
|
268
|
-
capacity: 1000
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
const user: User = await userCache.get('user:123', async () => {
|
|
272
|
-
// ่ผๅ
ฅๅจๅฟ
้ ๅๅณ User ๅๅฅ
|
|
273
|
-
return fetchUserFromAPI('123');
|
|
274
|
-
});
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## ้ฏ่ชค่็ๆฉๅถ
|
|
278
|
-
|
|
279
|
-
- **่ผๅ
ฅๅจๅคฑๆ**๏ผๅฆๆ่ผๅ
ฅๅจๅฝๆธๆๅบ็ฐๅธธ๏ผๅฐๆ็ๅฟซๅ้
็ฎๆ่ขซ่ชๅ็งป้ค
|
|
280
|
-
- **ไฟๅญๅจๅคฑๆ**๏ผๅฆๆไฟๅญๅจๅฝๆธๅคฑๆ๏ผๅฟซๅ้
็ฎไนๆ่ขซ็งป้ค๏ผ็ขบไฟ่ณๆไธ่ดๆง
|
|
281
|
-
- **ๆไฝ้้ฏ่ชค**๏ผPUT ๆไฝๆๅฟฝ็ฅๅไธๅๆไฝ็้ฏ่ชค๏ผ็ขบไฟๆฐๆไฝ่ฝๅค ็นผ็บ้ฒ่ก
|
|
282
|
-
- **้ฏ่ชคๆฅ่ช**๏ผๆๆ้ฏ่ชค้ฝๆ่ชๅ่จ้ๅฐๆงๅถๅฐ๏ผไพฟๆผ้ค้ฏ
|
|
283
|
-
|
|
284
|
-
## ่จๆถ้ซ็ฎก็
|
|
285
|
-
|
|
286
|
-
AsyncLRUCache ๅ
ทๅๅฎๅ็่จๆถ้ซ็ฎก็ๆฉๅถ๏ผ
|
|
287
|
-
|
|
288
|
-
- **่ชๅๆทๆฑฐ**๏ผ็ถๅฟซๅ้
็ฎๆธ้่ถ
้ๅฎน้้ๅถๆ๏ผ่ชๅ็งป้คๆไน
ๆชไฝฟ็จ็้
็ฎ
|
|
289
|
-
- **ๆๅๆธ
็**๏ผ`clear()` ๆนๆณๆๅพนๅบๆธ
็ๆๆ็ฏ้ป้ฃ็ต๏ผ้ฒๆญข่จๆถ้ซๆดฉๆผ
|
|
290
|
-
- **้ฏ่ชคๆธ
็**๏ผๆไฝๅคฑๆๆ่ชๅๆธ
็็ธ้ๅฟซๅ้
็ฎ
|
|
145
|
+
ๆญคๅฅไปถไปฅ TypeScript ๆฐๅฏซไธฆๅ
งๅปบๅๅฅๅฎฃๅๆช๏ผ็ก้ๅฆๅคๅฎ่ฃ `@types` ๅฅไปถใ
|
|
291
146
|
|
|
292
147
|
## ๆๆฌ
|
|
293
148
|
|
|
@@ -297,6 +152,3 @@ MIT
|
|
|
297
152
|
|
|
298
153
|
ๆญก่ฟๅจ [GitHub](https://github.com/wfp99/async-lru-cache) ไธๆๅบๅ้กๅ็ผ้ Pull Requestใ
|
|
299
154
|
|
|
300
|
-
## ไฝ่
|
|
301
|
-
|
|
302
|
-
Wang Feng Ping
|
package/dist/index.d.ts
CHANGED
|
@@ -5,10 +5,31 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module AsyncLRUCache
|
|
7
7
|
*/
|
|
8
|
+
/**
|
|
9
|
+
* Identifies which internal operation produced an error passed to `AsyncLRUCacheOption.onError`.
|
|
10
|
+
* - `loader`: The loader function passed to `get()` rejected.
|
|
11
|
+
* - `saver`: The saver function passed to `put()` rejected.
|
|
12
|
+
* - `put-chain`: A previous (already-settled) operation for the same key failed; this is a
|
|
13
|
+
* recoverable warning, since the new `put()` operation is still allowed to proceed.
|
|
14
|
+
*/
|
|
15
|
+
export type AsyncLRUCacheErrorSource = 'loader' | 'saver' | 'put-chain';
|
|
16
|
+
/**
|
|
17
|
+
* Context information supplied alongside an error to `AsyncLRUCacheOption.onError`.
|
|
18
|
+
*/
|
|
19
|
+
export interface AsyncLRUCacheErrorContext<K> {
|
|
20
|
+
/**
|
|
21
|
+
* The cache key associated with the failed operation.
|
|
22
|
+
*/
|
|
23
|
+
key: K;
|
|
24
|
+
/**
|
|
25
|
+
* Which internal operation produced the error.
|
|
26
|
+
*/
|
|
27
|
+
source: AsyncLRUCacheErrorSource;
|
|
28
|
+
}
|
|
8
29
|
/**
|
|
9
30
|
* Configuration options for the AsyncLRUCache.
|
|
10
31
|
*/
|
|
11
|
-
export interface AsyncLRUCacheOption {
|
|
32
|
+
export interface AsyncLRUCacheOption<K = unknown> {
|
|
12
33
|
/**
|
|
13
34
|
* Maximum capacity of the cache, this is the maximum number of items allowed.
|
|
14
35
|
* Must not be less than 10.
|
|
@@ -26,6 +47,14 @@ export interface AsyncLRUCacheOption {
|
|
|
26
47
|
* Setting this enables periodic background cleanup.
|
|
27
48
|
*/
|
|
28
49
|
cleanupIntervalMs?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Optional callback invoked whenever a loader/saver operation fails.
|
|
52
|
+
* When provided, this callback *replaces* the built-in `console.error`/`console.warn`
|
|
53
|
+
* logging, so you can forward errors to your own logger or monitoring system.
|
|
54
|
+
* If not provided, errors are logged to the console as before (default, backward-compatible behavior).
|
|
55
|
+
* This callback must not throw; any error thrown from it is ignored.
|
|
56
|
+
*/
|
|
57
|
+
onError?: (error: unknown, context: AsyncLRUCacheErrorContext<K>) => void;
|
|
29
58
|
}
|
|
30
59
|
/**
|
|
31
60
|
* Asynchronous LRU Cache class.
|
|
@@ -60,12 +89,16 @@ export declare class AsyncLRUCache<K, V> {
|
|
|
60
89
|
* Timer ID for periodic cleanup of expired entries.
|
|
61
90
|
*/
|
|
62
91
|
private cleanupTimer?;
|
|
92
|
+
/**
|
|
93
|
+
* Optional user-supplied error callback. When absent, errors are logged to the console.
|
|
94
|
+
*/
|
|
95
|
+
private readonly onError?;
|
|
63
96
|
/**
|
|
64
97
|
* Creates an instance of AsyncLRUCache with the specified options.
|
|
65
98
|
* @param option - The configuration options for the cache.
|
|
66
99
|
* @throws {Error} Throws an error if the provided capacity is less than 10.
|
|
67
100
|
*/
|
|
68
|
-
constructor(option: AsyncLRUCacheOption);
|
|
101
|
+
constructor(option: AsyncLRUCacheOption<K>);
|
|
69
102
|
/**
|
|
70
103
|
* Cleans up expired entries from the cache.
|
|
71
104
|
* This method removes all nodes that have exceeded their TTL.
|
|
@@ -100,6 +133,15 @@ export declare class AsyncLRUCache<K, V> {
|
|
|
100
133
|
* @param node - The node to add to the head of the list.
|
|
101
134
|
*/
|
|
102
135
|
private _addToHead;
|
|
136
|
+
/**
|
|
137
|
+
* Reports an error that occurred during a loader/saver operation.
|
|
138
|
+
* Delegates to the user-supplied `onError` callback if one was provided in the
|
|
139
|
+
* constructor options; otherwise falls back to logging via `console.error`/`console.warn`.
|
|
140
|
+
* @param error - The error that was thrown/rejected.
|
|
141
|
+
* @param key - The cache key associated with the failed operation.
|
|
142
|
+
* @param source - Which internal operation produced the error.
|
|
143
|
+
*/
|
|
144
|
+
private _reportError;
|
|
103
145
|
/**
|
|
104
146
|
* Retrieves data from the cache. If it does not exist, uses the loader to load it.
|
|
105
147
|
* Automatically merges concurrent requests for the same key.
|
|
@@ -109,6 +151,25 @@ export declare class AsyncLRUCache<K, V> {
|
|
|
109
151
|
* @returns A Promise that resolves to the required data.
|
|
110
152
|
*/
|
|
111
153
|
get(key: K, loader: () => Promise<V>, ttlMs?: number): Promise<V>;
|
|
154
|
+
/**
|
|
155
|
+
* Retrieves data from the cache without loading it on a miss.
|
|
156
|
+
* On a cache hit, this behaves like the loader-based overload: the entry is moved to
|
|
157
|
+
* the head of the LRU list, same as a normal `get()`/`has()` hit.
|
|
158
|
+
* On a cache miss (including an expired entry), it resolves to `undefined` without
|
|
159
|
+
* adding anything to the cache, so it does not affect the LRU order.
|
|
160
|
+
* @param key - Cache key.
|
|
161
|
+
* @returns A Promise that resolves to the cached value, or `undefined` on a miss.
|
|
162
|
+
*/
|
|
163
|
+
get(key: K): Promise<V | undefined>;
|
|
164
|
+
/**
|
|
165
|
+
* Returns the cached value for a key without triggering a loader and without
|
|
166
|
+
* affecting the LRU order, regardless of whether the key is a hit or a miss.
|
|
167
|
+
* If the entry has expired, it is evicted as a side effect of this check, the same
|
|
168
|
+
* way `has()` behaves; this does not count as an LRU-order-affecting access.
|
|
169
|
+
* @param key - Cache key.
|
|
170
|
+
* @returns The cached value's Promise if the key is present and not expired, otherwise `undefined`.
|
|
171
|
+
*/
|
|
172
|
+
peek(key: K): Promise<V> | undefined;
|
|
112
173
|
/**
|
|
113
174
|
* Puts a value into the cache, and optionally executes a saver function to persist it.
|
|
114
175
|
* This method serializes multiple put operations for the same key, ensuring they execute in order.
|
|
@@ -145,8 +206,15 @@ export declare class AsyncLRUCache<K, V> {
|
|
|
145
206
|
size(): number;
|
|
146
207
|
/**
|
|
147
208
|
* Checks if a key exists in the cache and is not expired.
|
|
209
|
+
*
|
|
210
|
+
* Note: this method is **not** side-effect-free. If the entry has expired, it is
|
|
211
|
+
* immediately evicted from the cache as part of this check (same as what would
|
|
212
|
+
* happen on the next `get()`/cleanup pass). It does **not** affect LRU order for
|
|
213
|
+
* entries that are still valid (unlike `get()`, calling `has()` does not move the
|
|
214
|
+
* entry to the head of the list).
|
|
148
215
|
* @param key - The key to check.
|
|
149
216
|
* @returns True if the key exists and is not expired, false otherwise.
|
|
150
217
|
*/
|
|
151
218
|
has(key: K): boolean;
|
|
152
219
|
}
|
|
220
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA8DH;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,yBAAyB,CAAC,CAAC;IAE3C;;OAEG;IACH,GAAG,EAAE,CAAC,CAAC;IAEP;;OAEG;IACH,MAAM,EAAE,wBAAwB,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,OAAO;IAE/C;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,yBAAyB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CAC1E;AAED;;;;;;;GAOG;AACH,qBAAa,aAAa,CAAC,CAAC,EAAE,CAAC;IAE9B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;IAEvC;;OAEG;IACH,OAAO,CAAC,OAAO,CAA4B;IAE3C;;OAEG;IACH,OAAO,CAAC,IAAI,CAA2B;IAEvC;;OAEG;IACH,OAAO,CAAC,IAAI,CAA2B;IAEvC;;OAEG;IACH,OAAO,CAAC,YAAY,CAAC,CAAiB;IAEtC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAkE;IAE3F;;;;OAIG;gBACS,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAkB1C;;;OAGG;IACH,OAAO,CAAC,eAAe;IAyBvB;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAStB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAQnB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAanB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAYlB;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;IA6BpB;;;;;;;OAOG;IACI,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAExE;;;;;;;;OAQG;IACI,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAiD1C;;;;;;;OAOG;IACI,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS;IAgB3C;;;;;;;;OAQG;IACI,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IA4DrG;;;OAGG;IACI,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI;IAW/B;;OAEG;IACI,KAAK,IAAI,IAAI;IA2BpB;;;OAGG;IACI,OAAO,IAAI,IAAI;IAatB;;;OAGG;IACI,cAAc,IAAI,IAAI;IAK7B;;;OAGG;IACI,IAAI,IAAI,MAAM;IAKrB;;;;;;;;;;OAUG;IACI,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;CAe3B"}
|
package/dist/index.js
CHANGED
|
@@ -79,6 +79,7 @@ class AsyncLRUCache {
|
|
|
79
79
|
throw new Error("Capacity must be at least 10.");
|
|
80
80
|
this.capacity = option.capacity;
|
|
81
81
|
this.defaultTtlMs = option.defaultTtlMs;
|
|
82
|
+
this.onError = option.onError;
|
|
82
83
|
// Setup periodic cleanup if specified
|
|
83
84
|
if (option.cleanupIntervalMs && option.cleanupIntervalMs > 0) {
|
|
84
85
|
this.cleanupTimer = setInterval(() => {
|
|
@@ -171,33 +172,60 @@ class AsyncLRUCache {
|
|
|
171
172
|
this.tail = node;
|
|
172
173
|
}
|
|
173
174
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* @param
|
|
178
|
-
* @param
|
|
179
|
-
* @
|
|
175
|
+
* Reports an error that occurred during a loader/saver operation.
|
|
176
|
+
* Delegates to the user-supplied `onError` callback if one was provided in the
|
|
177
|
+
* constructor options; otherwise falls back to logging via `console.error`/`console.warn`.
|
|
178
|
+
* @param error - The error that was thrown/rejected.
|
|
179
|
+
* @param key - The cache key associated with the failed operation.
|
|
180
|
+
* @param source - Which internal operation produced the error.
|
|
180
181
|
*/
|
|
182
|
+
_reportError(error, key, source) {
|
|
183
|
+
if (this.onError) {
|
|
184
|
+
try {
|
|
185
|
+
this.onError(error, { key, source });
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Swallow errors thrown by the user-supplied callback; it must not break cache operations.
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
switch (source) {
|
|
193
|
+
case 'loader':
|
|
194
|
+
console.error(`[AsyncLRUCache ERROR] Loader for key ${key} failed. Removing from cache.`, error);
|
|
195
|
+
break;
|
|
196
|
+
case 'saver':
|
|
197
|
+
console.error(`[AsyncLRUCache ERROR] Saver operation for key ${key} failed. Removing from cache.`, error);
|
|
198
|
+
break;
|
|
199
|
+
case 'put-chain':
|
|
200
|
+
console.warn(`[AsyncLRUCache WARN] Previous operation for key ${key} failed. Chaining new PUT operation.`, error?.message ?? error);
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
181
204
|
get(key, loader, ttlMs) {
|
|
182
205
|
const node = this.dataMap.get(key);
|
|
183
206
|
if (node) {
|
|
184
207
|
// Check if the node has expired
|
|
185
208
|
if (this._checkAndRemoveExpired(key, node)) {
|
|
186
|
-
// Node was expired and removed, proceed to load fresh data
|
|
209
|
+
// Node was expired and removed, proceed to load fresh data (if a loader is provided)
|
|
187
210
|
}
|
|
188
211
|
else {
|
|
189
212
|
this._moveToHead(node);
|
|
190
213
|
return node.value;
|
|
191
214
|
}
|
|
192
215
|
}
|
|
216
|
+
if (!loader) {
|
|
217
|
+
// No loader was provided and there is no valid cached value.
|
|
218
|
+
// Resolve to undefined without touching the cache or its LRU order.
|
|
219
|
+
return Promise.resolve(undefined);
|
|
220
|
+
}
|
|
193
221
|
const loadingPromise = loader();
|
|
194
|
-
const effectiveTtlMs = ttlMs
|
|
222
|
+
const effectiveTtlMs = ttlMs ?? this.defaultTtlMs;
|
|
195
223
|
const newNode = new Node(key, loadingPromise, effectiveTtlMs);
|
|
196
224
|
this.dataMap.set(key, newNode);
|
|
197
225
|
this._addToHead(newNode);
|
|
198
226
|
this._evictIfNeeded();
|
|
199
227
|
loadingPromise.catch(err => {
|
|
200
|
-
|
|
228
|
+
this._reportError(err, key, 'loader');
|
|
201
229
|
if (this.dataMap.get(key) === newNode) {
|
|
202
230
|
this.dataMap.delete(key);
|
|
203
231
|
this._removeNode(newNode);
|
|
@@ -205,6 +233,24 @@ class AsyncLRUCache {
|
|
|
205
233
|
});
|
|
206
234
|
return loadingPromise;
|
|
207
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* Returns the cached value for a key without triggering a loader and without
|
|
238
|
+
* affecting the LRU order, regardless of whether the key is a hit or a miss.
|
|
239
|
+
* If the entry has expired, it is evicted as a side effect of this check, the same
|
|
240
|
+
* way `has()` behaves; this does not count as an LRU-order-affecting access.
|
|
241
|
+
* @param key - Cache key.
|
|
242
|
+
* @returns The cached value's Promise if the key is present and not expired, otherwise `undefined`.
|
|
243
|
+
*/
|
|
244
|
+
peek(key) {
|
|
245
|
+
const node = this.dataMap.get(key);
|
|
246
|
+
if (!node) {
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
if (this._checkAndRemoveExpired(key, node)) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
return node.value;
|
|
253
|
+
}
|
|
208
254
|
/**
|
|
209
255
|
* Puts a value into the cache, and optionally executes a saver function to persist it.
|
|
210
256
|
* This method serializes multiple put operations for the same key, ensuring they execute in order.
|
|
@@ -218,7 +264,7 @@ class AsyncLRUCache {
|
|
|
218
264
|
const lastPromise = this.dataMap.has(key) ? this.dataMap.get(key).value : Promise.resolve(undefined);
|
|
219
265
|
const saverPromise = lastPromise.catch((err) => {
|
|
220
266
|
// Ignore previous operation errors, so the new operation can proceed.
|
|
221
|
-
|
|
267
|
+
this._reportError(err, key, 'put-chain');
|
|
222
268
|
})
|
|
223
269
|
.then(() => {
|
|
224
270
|
// After the previous operation (success or failure) completes, execute this saver.
|
|
@@ -230,7 +276,7 @@ class AsyncLRUCache {
|
|
|
230
276
|
return value;
|
|
231
277
|
});
|
|
232
278
|
let node = this.dataMap.get(key);
|
|
233
|
-
const effectiveTtlMs = ttlMs
|
|
279
|
+
const effectiveTtlMs = ttlMs ?? this.defaultTtlMs;
|
|
234
280
|
if (!node) {
|
|
235
281
|
node = new Node(key, saverPromise, effectiveTtlMs);
|
|
236
282
|
this.dataMap.set(key, node);
|
|
@@ -249,9 +295,8 @@ class AsyncLRUCache {
|
|
|
249
295
|
this._moveToHead(node);
|
|
250
296
|
}
|
|
251
297
|
saverPromise.catch(err => {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (((_a = this.dataMap.get(key)) === null || _a === void 0 ? void 0 : _a.value) === saverPromise) {
|
|
298
|
+
this._reportError(err, key, 'saver');
|
|
299
|
+
if (this.dataMap.get(key)?.value === saverPromise) {
|
|
255
300
|
this.dataMap.delete(key);
|
|
256
301
|
this._removeNode(node);
|
|
257
302
|
}
|
|
@@ -320,6 +365,12 @@ class AsyncLRUCache {
|
|
|
320
365
|
}
|
|
321
366
|
/**
|
|
322
367
|
* Checks if a key exists in the cache and is not expired.
|
|
368
|
+
*
|
|
369
|
+
* Note: this method is **not** side-effect-free. If the entry has expired, it is
|
|
370
|
+
* immediately evicted from the cache as part of this check (same as what would
|
|
371
|
+
* happen on the next `get()`/cleanup pass). It does **not** affect LRU order for
|
|
372
|
+
* entries that are still valid (unlike `get()`, calling `has()` does not move the
|
|
373
|
+
* entry to the head of the list).
|
|
323
374
|
* @param key - The key to check.
|
|
324
375
|
* @returns True if the key exists and is not expired, false otherwise.
|
|
325
376
|
*/
|
|
@@ -335,3 +386,4 @@ class AsyncLRUCache {
|
|
|
335
386
|
}
|
|
336
387
|
}
|
|
337
388
|
exports.AsyncLRUCache = AsyncLRUCache;
|
|
389
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wfp99/async-lru-cache",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A simple memory cache using the LRU algorithm and supporting asynchronous data access.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cache",
|
|
@@ -14,6 +14,13 @@
|
|
|
14
14
|
"type": "commonjs",
|
|
15
15
|
"main": "dist/index.js",
|
|
16
16
|
"types": "dist/index.d.ts",
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"require": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
17
24
|
"files": [
|
|
18
25
|
"dist/",
|
|
19
26
|
"README.md",
|
|
@@ -34,11 +41,13 @@
|
|
|
34
41
|
"scripts": {
|
|
35
42
|
"build": "tsc",
|
|
36
43
|
"clean": "rm -rf dist",
|
|
37
|
-
"prepublishOnly": "npm run clean && npm run build",
|
|
38
|
-
"test": "
|
|
44
|
+
"prepublishOnly": "npm run clean && npm run build && npm test",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"test:watch": "vitest"
|
|
39
47
|
},
|
|
40
48
|
"devDependencies": {
|
|
41
49
|
"@types/node": "^24.0.7",
|
|
42
|
-
"typescript": "^5.8.3"
|
|
50
|
+
"typescript": "^5.8.3",
|
|
51
|
+
"vitest": "^3.2.4"
|
|
43
52
|
}
|
|
44
53
|
}
|