0
# Asynchronous Functions
1
2
Specialized memoization for Node.js callback-style functions and promise-returning functions. Handles error cases, prevents caching of failed operations, and supports multiple promise handling modes for robust asynchronous operation caching.
3
4
## Capabilities
5
6
### Callback-Style Async Functions
7
8
Memoization for Node.js style callback functions where the last parameter is a callback with `(error, result)` signature.
9
10
```javascript { .api }
11
/**
12
* Enable memoization for Node.js callback-style async functions
13
* @param {boolean} async - Enable async callback handling
14
*/
15
const options = {
16
async: boolean
17
};
18
```
19
20
**Usage Examples:**
21
22
```javascript
23
const memoize = require("memoizee");
24
const fs = require("fs");
25
26
// Memoize file reading operations
27
const memoizedReadFile = memoize(fs.readFile, { async: true });
28
29
// First call - reads from disk
30
memoizedReadFile("./config.json", "utf8", (err, data) => {
31
if (err) console.error(err);
32
else console.log("File loaded:", data);
33
});
34
35
// Second call - returns cached result
36
memoizedReadFile("./config.json", "utf8", (err, data) => {
37
console.log("From cache:", data);
38
});
39
40
// Custom async function
41
function fetchUserData(userId, callback) {
42
setTimeout(() => {
43
if (userId === "invalid") {
44
callback(new Error("Invalid user ID"));
45
} else {
46
callback(null, { id: userId, name: `User ${userId}` });
47
}
48
}, 100);
49
}
50
51
const memoizedFetch = memoize(fetchUserData, { async: true });
52
53
memoizedFetch("123", (err, user) => {
54
console.log("User:", user); // Cached after first call
55
});
56
```
57
58
### Promise-Returning Functions
59
60
Memoization for functions that return promises, with configurable promise handling modes and error management.
61
62
```javascript { .api }
63
/**
64
* Enable memoization for promise-returning functions
65
* @param {boolean|string} promise - Enable promise handling with optional mode
66
*/
67
const options = {
68
promise: true | "then" | "then:finally" | "done" | "done:finally"
69
};
70
```
71
72
**Promise Handling Modes:**
73
74
- `true` or `"then"` (default): Uses `.then()` for promise resolution
75
- `"then:finally"`: Uses `.then()` and `.finally()` for promise resolution
76
- `"done"`: Uses `.done()` method (requires promise library support)
77
- `"done:finally"`: Uses both `.done()` and `.finally()` methods
78
79
**Usage Examples:**
80
81
```javascript
82
const memoize = require("memoizee");
83
84
// Basic promise memoization
85
async function fetchData(url) {
86
const response = await fetch(url);
87
return response.json();
88
}
89
90
const memoizedFetch = memoize(fetchData, { promise: true });
91
92
// First call - makes HTTP request
93
memoizedFetch("https://api.example.com/data")
94
.then(data => console.log("Fetched:", data));
95
96
// Second call - returns cached promise result
97
memoizedFetch("https://api.example.com/data")
98
.then(data => console.log("Cached:", data));
99
100
// With custom promise mode
101
const memoizedWithDone = memoize(fetchData, { promise: "done" });
102
103
// Error handling - failed promises are not cached
104
async function failingFunction(shouldFail) {
105
if (shouldFail) {
106
throw new Error("Operation failed");
107
}
108
return "Success";
109
}
110
111
const memoizedFailing = memoize(failingFunction, { promise: true });
112
113
memoizedFailing(true)
114
.catch(err => console.log("Error not cached"));
115
116
memoizedFailing(false)
117
.then(result => console.log("Success cached:", result));
118
```
119
120
### Combined Async Configuration
121
122
Using async memoization with other memoization features like cache expiration and size limits.
123
124
```javascript { .api }
125
/**
126
* Combine async support with other memoization options
127
*/
128
const combinedOptions = {
129
async: boolean, // or promise: boolean|string
130
maxAge: number, // Cache expiration in milliseconds
131
max: number, // Maximum cache entries
132
preFetch: boolean // Pre-fetch before expiration
133
};
134
```
135
136
**Usage Examples:**
137
138
```javascript
139
// Async with cache expiration
140
const memoizedWithTTL = memoize(asyncFunction, {
141
async: true,
142
maxAge: 60000, // 1 minute TTL
143
preFetch: true // Refresh cache before expiration
144
});
145
146
// Promise with size limit
147
const memoizedPromiseWithLimit = memoize(promiseFunction, {
148
promise: true,
149
max: 50, // Keep only 50 cached results
150
dispose: (result) => {
151
// Cleanup when entries are evicted
152
if (result && result.cleanup) result.cleanup();
153
}
154
});
155
156
// Async with custom normalizer for object arguments
157
const memoizedAsyncNormalized = memoize(asyncDbQuery, {
158
async: true,
159
normalizer: (args) => JSON.stringify(args[0]) // First arg is query object
160
});
161
```
162
163
## Error Handling
164
165
### Failed Operations Are Not Cached
166
167
Both async and promise modes automatically exclude failed operations from the cache:
168
169
```javascript
170
const memoize = require("memoizee");
171
172
// Callback-style: errors are not cached
173
const memoizedAsync = memoize((id, callback) => {
174
if (id === "fail") {
175
callback(new Error("Failed"));
176
} else {
177
callback(null, `Result for ${id}`);
178
}
179
}, { async: true });
180
181
// Promise-style: rejections are not cached
182
const memoizedPromise = memoize(async (id) => {
183
if (id === "fail") {
184
throw new Error("Failed");
185
}
186
return `Result for ${id}`;
187
}, { promise: true });
188
```
189
190
### Cache Events for Async Operations
191
192
Async memoized functions emit special events for monitoring:
193
194
```javascript { .api }
195
/**
196
* Async-specific cache events
197
*/
198
memoizedFunction.on("setasync", (id, callbackCount) => {
199
// Called when async result is cached
200
});
201
202
memoizedFunction.on("getasync", (id, args, context) => {
203
// Called when async result is retrieved from cache
204
});
205
206
memoizedFunction.on("deleteasync", (id, resultArray) => {
207
// Called when async cache entry is deleted
208
});
209
210
memoizedFunction.on("clearasync", (cache) => {
211
// Called when async cache is cleared
212
});
213
```
214
215
## Advanced Async Patterns
216
217
### Concurrent Request Deduplication
218
219
Multiple concurrent calls with same arguments will be deduplicated:
220
221
```javascript
222
const memoizedFetch = memoize(fetchData, { promise: true });
223
224
// These three calls will result in only one actual fetch
225
const promise1 = memoizedFetch("same-url");
226
const promise2 = memoizedFetch("same-url");
227
const promise3 = memoizedFetch("same-url");
228
229
// All three promises will resolve with the same result
230
Promise.all([promise1, promise2, promise3])
231
.then(results => {
232
// results[0] === results[1] === results[2]
233
});
234
```
235
236
### Pre-fetching for Cache Refresh
237
238
Automatically refresh cache entries before they expire:
239
240
```javascript
241
const memoizedWithPrefetch = memoize(asyncFunction, {
242
async: true,
243
maxAge: 60000, // 1 minute expiration
244
preFetch: 0.8 // Start refresh when 20% of TTL remains
245
});
246
247
// Cache will be refreshed in background when accessed near expiration
248
```
249
250
### Custom Promise Library Integration
251
252
For promise libraries that implement `.done()` method:
253
254
```javascript
255
const Bluebird = require("bluebird");
256
257
function promiseFunction() {
258
return new Bluebird((resolve) => {
259
setTimeout(() => resolve("result"), 100);
260
});
261
}
262
263
const memoized = memoize(promiseFunction, {
264
promise: "done" // Uses Bluebird's .done() method
265
});
266
```
267
268
## Performance Considerations
269
270
### Memory Usage with Async Caching
271
272
Async caching may use additional memory for managing pending operations:
273
274
```javascript
275
// Use size limits for async operations with high concurrency
276
const memoized = memoize(asyncOp, {
277
async: true,
278
max: 100, // Limit concurrent + cached operations
279
maxAge: 30000 // Clean up old entries
280
});
281
```
282
283
### Choosing Promise Modes
284
285
- **`"then"`** (default): Most compatible, but may suppress unhandled rejection warnings
286
- **`"done"`**: Preserves error handling characteristics of promise library
287
- **`"done:finally"`**: Best for libraries that support both, minimal side effects