@depup/p-memoize 8.0.0-depup.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 +31 -0
- package/changes.json +10 -0
- package/dist/index.d.ts +141 -0
- package/dist/index.js +139 -0
- package/license +9 -0
- package/package.json +104 -0
- package/readme.md +183 -0
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# @depup/p-memoize
|
|
2
|
+
|
|
3
|
+
> Dependency-bumped version of [p-memoize](https://www.npmjs.com/package/p-memoize)
|
|
4
|
+
|
|
5
|
+
Generated by [DepUp](https://github.com/depup/npm) -- all production
|
|
6
|
+
dependencies bumped to latest versions.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @depup/p-memoize
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Field | Value |
|
|
15
|
+
|-------|-------|
|
|
16
|
+
| Original | [p-memoize](https://www.npmjs.com/package/p-memoize) @ 8.0.0 |
|
|
17
|
+
| Processed | 2026-03-19 |
|
|
18
|
+
| Smoke test | passed |
|
|
19
|
+
| Deps updated | 1 |
|
|
20
|
+
|
|
21
|
+
## Dependency Changes
|
|
22
|
+
|
|
23
|
+
| Dependency | From | To |
|
|
24
|
+
|------------|------|-----|
|
|
25
|
+
| type-fest | ^4.41.0 | ^5.4.4 |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
Source: https://github.com/depup/npm | Original: https://www.npmjs.com/package/p-memoize
|
|
30
|
+
|
|
31
|
+
License inherited from the original package.
|
package/changes.json
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { AsyncReturnType } from 'type-fest';
|
|
2
|
+
export type AnyAsyncFunction = (...arguments_: readonly any[]) => Promise<unknown | void>;
|
|
3
|
+
export type CacheStorage<KeyType, ValueType> = {
|
|
4
|
+
has: (key: KeyType) => Promise<boolean> | boolean;
|
|
5
|
+
get: (key: KeyType) => Promise<ValueType | undefined> | ValueType | undefined;
|
|
6
|
+
set: (key: KeyType, value: ValueType) => Promise<unknown> | unknown;
|
|
7
|
+
delete: (key: KeyType) => unknown;
|
|
8
|
+
clear?: () => unknown;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
Controls whether a fulfilled value should be written to the cache.
|
|
12
|
+
*/
|
|
13
|
+
export type ShouldCache<KeyType, ValueType, ArgumentsList extends readonly unknown[] = readonly unknown[]> = (value: ValueType, context: {
|
|
14
|
+
key: KeyType;
|
|
15
|
+
argumentsList: ArgumentsList;
|
|
16
|
+
}) => boolean | Promise<boolean>;
|
|
17
|
+
export type Options<FunctionToMemoize extends AnyAsyncFunction, CacheKeyType> = {
|
|
18
|
+
/**
|
|
19
|
+
Determines the cache key for storing the result based on the function arguments. By default, __only the first argument is considered__ and it only works with [primitives](https://developer.mozilla.org/docs/Glossary/Primitive).
|
|
20
|
+
|
|
21
|
+
A `cacheKey` function can return any type supported by `Map` (or whatever structure you use in the `cache` option).
|
|
22
|
+
|
|
23
|
+
You can have it cache **all** the arguments by value with `JSON.stringify`, if they are compatible:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
import pMemoize from 'p-memoize';
|
|
27
|
+
|
|
28
|
+
pMemoize(function_, {cacheKey: JSON.stringify});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or you can use a more full-featured serializer like [serialize-javascript](https://github.com/yahoo/serialize-javascript) to add support for `RegExp`, `Date` and so on.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
import pMemoize from 'p-memoize';
|
|
35
|
+
import serializeJavascript from 'serialize-javascript';
|
|
36
|
+
|
|
37
|
+
pMemoize(function_, {cacheKey: serializeJavascript});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
@default arguments_ => arguments_[0]
|
|
41
|
+
@example arguments_ => JSON.stringify(arguments_)
|
|
42
|
+
*/
|
|
43
|
+
readonly cacheKey?: (arguments_: Parameters<FunctionToMemoize>) => CacheKeyType;
|
|
44
|
+
/**
|
|
45
|
+
Use a different cache storage. Must implement the following methods: `.has(key)`, `.get(key)`, `.set(key, value)`, `.delete(key)`, and optionally `.clear()`. You could for example use a `WeakMap` instead or [`quick-lru`](https://github.com/sindresorhus/quick-lru) for a LRU cache. To disable caching so that only concurrent executions resolve with the same value, pass `false`.
|
|
46
|
+
|
|
47
|
+
@default new Map()
|
|
48
|
+
@example new WeakMap()
|
|
49
|
+
*/
|
|
50
|
+
readonly cache?: CacheStorage<CacheKeyType, AsyncReturnType<FunctionToMemoize>> | false;
|
|
51
|
+
/**
|
|
52
|
+
Controls whether a fulfilled value should be written to the cache.
|
|
53
|
+
|
|
54
|
+
It runs after the function fulfills and before `cache.set`.
|
|
55
|
+
|
|
56
|
+
- Omit to keep current behavior (always write).
|
|
57
|
+
- Return `false` to skip writing to the cache (in-flight de-duplication is still cleared).
|
|
58
|
+
- Throw or reject to propagate the error and skip caching.
|
|
59
|
+
|
|
60
|
+
@example
|
|
61
|
+
```
|
|
62
|
+
import pMemoize from 'p-memoize';
|
|
63
|
+
|
|
64
|
+
// Only cache defined values
|
|
65
|
+
const getMaybe = pMemoize(async key => db.get(key), {
|
|
66
|
+
shouldCache: value => value !== undefined,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Only cache non-empty arrays
|
|
70
|
+
const search = pMemoize(async query => fetchResults(query), {
|
|
71
|
+
shouldCache: value => Array.isArray(value) && value.length > 0,
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Note: This only affects writes; reads from the cache are unchanged.
|
|
76
|
+
*/
|
|
77
|
+
readonly shouldCache?: ShouldCache<CacheKeyType, AsyncReturnType<FunctionToMemoize>, Parameters<FunctionToMemoize>>;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
[Memoize](https://en.wikipedia.org/wiki/Memoization) functions - An optimization used to speed up consecutive function calls by caching the result of calls with identical input.
|
|
81
|
+
|
|
82
|
+
@param fn - Function to be memoized.
|
|
83
|
+
|
|
84
|
+
@example
|
|
85
|
+
```
|
|
86
|
+
import {setTimeout as delay} from 'node:timer/promises';
|
|
87
|
+
import pMemoize from 'p-memoize';
|
|
88
|
+
import got from 'got';
|
|
89
|
+
|
|
90
|
+
const memoizedGot = pMemoize(got);
|
|
91
|
+
|
|
92
|
+
await memoizedGot('https://sindresorhus.com');
|
|
93
|
+
|
|
94
|
+
// This call is cached
|
|
95
|
+
await memoizedGot('https://sindresorhus.com');
|
|
96
|
+
|
|
97
|
+
await delay(2000);
|
|
98
|
+
|
|
99
|
+
// This call is not cached as the cache has expired
|
|
100
|
+
await memoizedGot('https://sindresorhus.com');
|
|
101
|
+
```
|
|
102
|
+
*/
|
|
103
|
+
export default function pMemoize<FunctionToMemoize extends AnyAsyncFunction, CacheKeyType = Parameters<FunctionToMemoize>[0], OptionsType = Options<FunctionToMemoize, CacheKeyType>>(fn: FunctionToMemoize, options?: OptionsType & Options<FunctionToMemoize, CacheKeyType>): FunctionToMemoize;
|
|
104
|
+
/**
|
|
105
|
+
- Only class methods are supported; regular functions are not part of the decorators proposals.
|
|
106
|
+
- Uses the new ECMAScript decorators (TypeScript 5.0+). Legacy `experimentalDecorators` are not supported.
|
|
107
|
+
- Babel’s legacy decorators are not supported.
|
|
108
|
+
- Private methods are not supported.
|
|
109
|
+
|
|
110
|
+
@returns A decorator to memoize class methods or static class methods.
|
|
111
|
+
|
|
112
|
+
@example
|
|
113
|
+
```
|
|
114
|
+
import {pMemoizeDecorator} from 'p-memoize';
|
|
115
|
+
|
|
116
|
+
class Example {
|
|
117
|
+
index = 0
|
|
118
|
+
|
|
119
|
+
@pMemoizeDecorator()
|
|
120
|
+
async counter() {
|
|
121
|
+
return ++this.index;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
class ExampleWithOptions {
|
|
126
|
+
index = 0
|
|
127
|
+
|
|
128
|
+
@pMemoizeDecorator()
|
|
129
|
+
async counter() {
|
|
130
|
+
return ++this.index;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
*/
|
|
135
|
+
export declare function pMemoizeDecorator<FunctionToMemoize extends AnyAsyncFunction = AnyAsyncFunction, CacheKeyType = Parameters<FunctionToMemoize>[0]>(options?: Options<NoInfer<FunctionToMemoize>, NoInfer<CacheKeyType>>): <This, Value extends FunctionToMemoize>(value: Value, context: ClassMethodDecoratorContext<This, Value>) => void;
|
|
136
|
+
/**
|
|
137
|
+
Clear all cached data of a memoized function.
|
|
138
|
+
|
|
139
|
+
@param fn - Memoized function.
|
|
140
|
+
*/
|
|
141
|
+
export declare function pMemoizeClear(fn: AnyAsyncFunction): void;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import mimicFunction from 'mimic-function';
|
|
2
|
+
const cacheStore = new WeakMap();
|
|
3
|
+
/**
|
|
4
|
+
[Memoize](https://en.wikipedia.org/wiki/Memoization) functions - An optimization used to speed up consecutive function calls by caching the result of calls with identical input.
|
|
5
|
+
|
|
6
|
+
@param fn - Function to be memoized.
|
|
7
|
+
|
|
8
|
+
@example
|
|
9
|
+
```
|
|
10
|
+
import {setTimeout as delay} from 'node:timer/promises';
|
|
11
|
+
import pMemoize from 'p-memoize';
|
|
12
|
+
import got from 'got';
|
|
13
|
+
|
|
14
|
+
const memoizedGot = pMemoize(got);
|
|
15
|
+
|
|
16
|
+
await memoizedGot('https://sindresorhus.com');
|
|
17
|
+
|
|
18
|
+
// This call is cached
|
|
19
|
+
await memoizedGot('https://sindresorhus.com');
|
|
20
|
+
|
|
21
|
+
await delay(2000);
|
|
22
|
+
|
|
23
|
+
// This call is not cached as the cache has expired
|
|
24
|
+
await memoizedGot('https://sindresorhus.com');
|
|
25
|
+
```
|
|
26
|
+
*/
|
|
27
|
+
export default function pMemoize(fn, options) {
|
|
28
|
+
const defaultCacheKey = ([firstArgument]) => firstArgument;
|
|
29
|
+
const { cacheKey = defaultCacheKey, cache = new Map(), } = options ?? {};
|
|
30
|
+
// Promise objects can't be serialized so we keep track of them internally and only provide their resolved values to `cache`
|
|
31
|
+
// `Promise<AsyncReturnType<FunctionToMemoize>>` is used instead of `ReturnType<FunctionToMemoize>` because promise properties are not kept
|
|
32
|
+
const promiseCache = new Map();
|
|
33
|
+
const memoized = function (...arguments_) {
|
|
34
|
+
const key = cacheKey(arguments_);
|
|
35
|
+
if (promiseCache.has(key)) {
|
|
36
|
+
return promiseCache.get(key);
|
|
37
|
+
}
|
|
38
|
+
const promise = (async () => {
|
|
39
|
+
try {
|
|
40
|
+
if (cache && await cache.has(key)) {
|
|
41
|
+
return (await cache.get(key));
|
|
42
|
+
}
|
|
43
|
+
const promise = fn.apply(this, arguments_);
|
|
44
|
+
const result = await promise;
|
|
45
|
+
try {
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
if (cache) {
|
|
50
|
+
const allow = options?.shouldCache
|
|
51
|
+
? await options.shouldCache(result, { key, argumentsList: arguments_ })
|
|
52
|
+
: true;
|
|
53
|
+
if (allow) {
|
|
54
|
+
await cache.set(key, result);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
promiseCache.delete(key);
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
promiseCache.set(key, promise);
|
|
64
|
+
return promise;
|
|
65
|
+
};
|
|
66
|
+
mimicFunction(memoized, fn, {
|
|
67
|
+
ignoreNonConfigurable: true,
|
|
68
|
+
});
|
|
69
|
+
cacheStore.set(memoized, cache);
|
|
70
|
+
return memoized;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
- Only class methods are supported; regular functions are not part of the decorators proposals.
|
|
74
|
+
- Uses the new ECMAScript decorators (TypeScript 5.0+). Legacy `experimentalDecorators` are not supported.
|
|
75
|
+
- Babel’s legacy decorators are not supported.
|
|
76
|
+
- Private methods are not supported.
|
|
77
|
+
|
|
78
|
+
@returns A decorator to memoize class methods or static class methods.
|
|
79
|
+
|
|
80
|
+
@example
|
|
81
|
+
```
|
|
82
|
+
import {pMemoizeDecorator} from 'p-memoize';
|
|
83
|
+
|
|
84
|
+
class Example {
|
|
85
|
+
index = 0
|
|
86
|
+
|
|
87
|
+
@pMemoizeDecorator()
|
|
88
|
+
async counter() {
|
|
89
|
+
return ++this.index;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
class ExampleWithOptions {
|
|
94
|
+
index = 0
|
|
95
|
+
|
|
96
|
+
@pMemoizeDecorator()
|
|
97
|
+
async counter() {
|
|
98
|
+
return ++this.index;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
*/
|
|
103
|
+
export function pMemoizeDecorator(options = {}) {
|
|
104
|
+
return function (value, context) {
|
|
105
|
+
if (context.kind !== 'method') {
|
|
106
|
+
throw new TypeError('pMemoizeDecorator can only decorate methods');
|
|
107
|
+
}
|
|
108
|
+
if (context.private) {
|
|
109
|
+
throw new TypeError('pMemoizeDecorator cannot decorate private methods');
|
|
110
|
+
}
|
|
111
|
+
context.addInitializer(function () {
|
|
112
|
+
const memoizedMethod = pMemoize(value, options);
|
|
113
|
+
Object.defineProperty(this, context.name, {
|
|
114
|
+
configurable: true,
|
|
115
|
+
writable: true,
|
|
116
|
+
enumerable: false,
|
|
117
|
+
value: memoizedMethod,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
Clear all cached data of a memoized function.
|
|
124
|
+
|
|
125
|
+
@param fn - Memoized function.
|
|
126
|
+
*/
|
|
127
|
+
export function pMemoizeClear(fn) {
|
|
128
|
+
if (!cacheStore.has(fn)) {
|
|
129
|
+
throw new TypeError('Can\'t clear a function that was not memoized!');
|
|
130
|
+
}
|
|
131
|
+
const cache = cacheStore.get(fn);
|
|
132
|
+
if (!cache) {
|
|
133
|
+
throw new TypeError('Can\'t clear a function that doesn\'t use a cache!');
|
|
134
|
+
}
|
|
135
|
+
if (typeof cache.clear !== 'function') {
|
|
136
|
+
throw new TypeError('The cache Map can\'t be cleared!');
|
|
137
|
+
}
|
|
138
|
+
cache.clear();
|
|
139
|
+
}
|
package/license
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/package.json
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@depup/p-memoize",
|
|
3
|
+
"version": "8.0.0-depup.0",
|
|
4
|
+
"description": "Memoize promise-returning & async functions (with updated dependencies)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": "sindresorhus/p-memoize",
|
|
7
|
+
"funding": "https://github.com/sindresorhus/p-memoize?sponsor=1",
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "Sindre Sorhus",
|
|
10
|
+
"email": "sindresorhus@gmail.com",
|
|
11
|
+
"url": "https://sindresorhus.com"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=20"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"test": "xo && ava && npm run build && tsd",
|
|
25
|
+
"build": "del-cli dist && tsc"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"changes.json",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"keywords": [
|
|
33
|
+
"p-memoize",
|
|
34
|
+
"depup",
|
|
35
|
+
"updated-dependencies",
|
|
36
|
+
"security",
|
|
37
|
+
"latest",
|
|
38
|
+
"patched",
|
|
39
|
+
"promise",
|
|
40
|
+
"memoize",
|
|
41
|
+
"mem",
|
|
42
|
+
"memoization",
|
|
43
|
+
"function",
|
|
44
|
+
"cache",
|
|
45
|
+
"caching",
|
|
46
|
+
"optimize",
|
|
47
|
+
"performance",
|
|
48
|
+
"ttl",
|
|
49
|
+
"expire",
|
|
50
|
+
"async",
|
|
51
|
+
"await",
|
|
52
|
+
"promises",
|
|
53
|
+
"time",
|
|
54
|
+
"out",
|
|
55
|
+
"cancel",
|
|
56
|
+
"bluebird"
|
|
57
|
+
],
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"mimic-function": "^5.0.1",
|
|
60
|
+
"type-fest": "^5.4.4"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@sindresorhus/tsconfig": "^8.0.1",
|
|
64
|
+
"@types/serialize-javascript": "^5.0.4",
|
|
65
|
+
"ava": "^6.4.1",
|
|
66
|
+
"del-cli": "^6.0.0",
|
|
67
|
+
"delay": "^6.0.0",
|
|
68
|
+
"p-defer": "^4.0.1",
|
|
69
|
+
"p-state": "^2.0.1",
|
|
70
|
+
"serialize-javascript": "^6.0.2",
|
|
71
|
+
"tsd": "^0.33.0",
|
|
72
|
+
"tsimp": "^2.0.12",
|
|
73
|
+
"xo": "^1.2.1"
|
|
74
|
+
},
|
|
75
|
+
"ava": {
|
|
76
|
+
"environmentVariables": {
|
|
77
|
+
"TSIMP_DIAG": "ignore"
|
|
78
|
+
},
|
|
79
|
+
"extensions": {
|
|
80
|
+
"ts": "module"
|
|
81
|
+
},
|
|
82
|
+
"nodeArguments": [
|
|
83
|
+
"--import=tsimp/import"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
"xo": {
|
|
87
|
+
"rules": {
|
|
88
|
+
"@typescript-eslint/no-redundant-type-constituents": "off"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"depup": {
|
|
92
|
+
"changes": {
|
|
93
|
+
"type-fest": {
|
|
94
|
+
"from": "^4.41.0",
|
|
95
|
+
"to": "^5.4.4"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"depsUpdated": 1,
|
|
99
|
+
"originalPackage": "p-memoize",
|
|
100
|
+
"originalVersion": "8.0.0",
|
|
101
|
+
"processedAt": "2026-03-19T03:31:53.580Z",
|
|
102
|
+
"smokeTest": "passed"
|
|
103
|
+
}
|
|
104
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# p-memoize
|
|
2
|
+
|
|
3
|
+
> [Memoize](https://en.wikipedia.org/wiki/Memoization) promise-returning & async functions
|
|
4
|
+
|
|
5
|
+
Useful for speeding up consecutive function calls by caching the result of calls with identical input.
|
|
6
|
+
|
|
7
|
+
<!-- Please keep this section in sync with https://github.com/sindresorhus/memoize/blob/main/readme.md -->
|
|
8
|
+
|
|
9
|
+
By default, **only the memoized function's first argument is considered** via strict equality comparison. If you need to cache multiple arguments or cache `object`s *by value*, have a look at alternative [caching strategies](#caching-strategy) below.
|
|
10
|
+
|
|
11
|
+
This package is similar to [memoize](https://github.com/sindresorhus/memoize) but with async-specific enhancements; in particular, it allows for asynchronous caches and does not cache rejected promises.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install p-memoize
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import pMemoize from 'p-memoize';
|
|
23
|
+
import got from 'got';
|
|
24
|
+
|
|
25
|
+
const memoizedGot = pMemoize(got);
|
|
26
|
+
|
|
27
|
+
await memoizedGot('https://sindresorhus.com');
|
|
28
|
+
|
|
29
|
+
// This call is cached
|
|
30
|
+
await memoizedGot('https://sindresorhus.com');
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Caching strategy
|
|
34
|
+
|
|
35
|
+
Similar to the [caching strategy for `memoize`](https://github.com/sindresorhus/memoize#options) with the following exceptions:
|
|
36
|
+
|
|
37
|
+
- Promises returned from a memoized function are locally cached until resolving, when their value is added to `cache`. Special properties assigned to a returned promise will not be kept after resolution and every promise may need to resolve with a serializable object if caching results in a database.
|
|
38
|
+
- `.get()`, `.has()` and `.set()` methods on `cache` can run asynchronously by returning a promise.
|
|
39
|
+
- Instead of `.set()` being provided an object with the properties `value` and `maxAge`, it will only be provided `value` as the first argument. If you want to implement time-based expiry, consider [doing so in `cache`](#time-based-cache-expiration).
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
### pMemoize(fn, options?)
|
|
44
|
+
|
|
45
|
+
Returns a memoized version of the given function.
|
|
46
|
+
|
|
47
|
+
#### fn
|
|
48
|
+
|
|
49
|
+
Type: `Function`
|
|
50
|
+
|
|
51
|
+
Promise-returning or async function to be memoized.
|
|
52
|
+
|
|
53
|
+
#### options
|
|
54
|
+
|
|
55
|
+
Type: `object`
|
|
56
|
+
|
|
57
|
+
##### cacheKey
|
|
58
|
+
|
|
59
|
+
Type: `Function`\
|
|
60
|
+
Default: `arguments_ => arguments_[0]`\
|
|
61
|
+
Example: `arguments_ => JSON.stringify(arguments_)`
|
|
62
|
+
|
|
63
|
+
Determines the cache key for storing the result based on the function arguments. By default, **only the first argument is considered**.
|
|
64
|
+
|
|
65
|
+
A `cacheKey` function can return any type supported by `Map` (or whatever structure you use in the `cache` option).
|
|
66
|
+
|
|
67
|
+
See the [caching strategy](#caching-strategy) section for more information.
|
|
68
|
+
|
|
69
|
+
##### cache
|
|
70
|
+
|
|
71
|
+
Type: `object | false`\
|
|
72
|
+
Default: `new Map()`
|
|
73
|
+
|
|
74
|
+
Use a different cache storage. Must implement the following methods: `.has(key)`, `.get(key)`, `.set(key, value)`, `.delete(key)`, and optionally `.clear()`. You could for example use a `WeakMap` instead or [`quick-lru`](https://github.com/sindresorhus/quick-lru) for a LRU cache. To disable caching so that only concurrent executions resolve with the same value, pass `false`.
|
|
75
|
+
|
|
76
|
+
See the [caching strategy](https://github.com/sindresorhus/mem#caching-strategy) section in the `mem` package for more information.
|
|
77
|
+
|
|
78
|
+
##### shouldCache
|
|
79
|
+
|
|
80
|
+
Type: `(value, {key, argumentsList}) => boolean | Promise<boolean>`
|
|
81
|
+
|
|
82
|
+
Controls whether a fulfilled value should be written to the cache.
|
|
83
|
+
|
|
84
|
+
It runs after the function fulfills and before `cache.set`.
|
|
85
|
+
|
|
86
|
+
- Omit to keep current behavior (always write).
|
|
87
|
+
- Return `false` to skip writing to the cache (in-flight de-duplication is still cleared).
|
|
88
|
+
- Throw or reject to propagate the error and skip caching.
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
import pMemoize from 'p-memoize';
|
|
92
|
+
|
|
93
|
+
// Only cache defined values
|
|
94
|
+
const getMaybe = pMemoize(async key => db.get(key), {
|
|
95
|
+
shouldCache: value => value !== undefined,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Only cache non-empty arrays
|
|
99
|
+
const search = pMemoize(async query => fetchResults(query), {
|
|
100
|
+
shouldCache: value => Array.isArray(value) && value.length > 0,
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Note: Affects only writes; reads from the cache are unchanged.
|
|
105
|
+
|
|
106
|
+
### pMemoizeDecorator(options)
|
|
107
|
+
|
|
108
|
+
Returns a decorator to memoize class methods (instance and static).
|
|
109
|
+
|
|
110
|
+
Notes:
|
|
111
|
+
|
|
112
|
+
- Only class methods are supported; regular functions are not part of the decorators proposals.
|
|
113
|
+
- Requires the new ECMAScript decorators (TypeScript 5.0+). Legacy `experimentalDecorators` are not supported.
|
|
114
|
+
- Babel’s legacy decorators are not supported as they implement a different proposal variant.
|
|
115
|
+
- Private methods are not supported.
|
|
116
|
+
|
|
117
|
+
#### options
|
|
118
|
+
|
|
119
|
+
Type: `object`
|
|
120
|
+
|
|
121
|
+
Same as options for `pMemoize()`.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import {pMemoizeDecorator} from 'p-memoize';
|
|
125
|
+
|
|
126
|
+
class Example {
|
|
127
|
+
index = 0
|
|
128
|
+
|
|
129
|
+
@pMemoizeDecorator()
|
|
130
|
+
async counter() {
|
|
131
|
+
return ++this.index;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
class ExampleWithOptions {
|
|
136
|
+
index = 0
|
|
137
|
+
|
|
138
|
+
@pMemoizeDecorator()
|
|
139
|
+
async counter() {
|
|
140
|
+
return ++this.index;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The decorator memoizes per-instance. You can clear the cache for an instance method using `pMemoizeClear(instance.method)`.
|
|
146
|
+
|
|
147
|
+
### pMemoizeClear(memoized)
|
|
148
|
+
|
|
149
|
+
Clear all cached data of a memoized function.
|
|
150
|
+
|
|
151
|
+
It will throw when given a non-memoized function.
|
|
152
|
+
|
|
153
|
+
## Tips
|
|
154
|
+
|
|
155
|
+
### Time-based cache expiration
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
import pMemoize from 'p-memoize';
|
|
159
|
+
import ExpiryMap from 'expiry-map';
|
|
160
|
+
import got from 'got';
|
|
161
|
+
|
|
162
|
+
const cache = new ExpiryMap(10000); // Cached values expire after 10 seconds
|
|
163
|
+
|
|
164
|
+
const memoizedGot = pMemoize(got, {cache});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Caching promise rejections
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
import pMemoize from 'p-memoize';
|
|
171
|
+
import pReflect from 'p-reflect';
|
|
172
|
+
|
|
173
|
+
const memoizedGot = pMemoize(async (url, options) => pReflect(got(url, options)));
|
|
174
|
+
|
|
175
|
+
await memoizedGot('https://example.com');
|
|
176
|
+
// {isFulfilled: true, isRejected: false, value: '...'}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Related
|
|
180
|
+
|
|
181
|
+
- [p-debounce](https://github.com/sindresorhus/p-debounce) - Debounce promise-returning & async functions
|
|
182
|
+
- [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
|
|
183
|
+
- [More…](https://github.com/sindresorhus/promise-fun)
|