This repository has been archived by the owner on Mar 9, 2023. It is now read-only.
forked from jfromaniello/lru-memoizer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
143 lines (114 loc) · 3.53 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
const LRU = require('lru-cache');
const lru_params = [ 'max', 'maxAge', 'length', 'dispose', 'stale' ];
const deepFreeze = require('./lib/freeze');
const vfs = require('very-fast-args');
const _assignIn = require('lodash.assignin');
const _pick = require('lodash.pick');
const _cloneDeep = require('lodash.clonedeep');
const _toArray = require('lodash.toarray');
module.exports = function (options) {
const cache = new LRU(_pick(options, lru_params));
const load = options.load;
const hash = options.hash;
const bypass = options.bypass;
const itemMaxAge = options.itemMaxAge;
const freeze = options.freeze;
const clone = options.clone;
const loading = new Map();
if (options.disable) {
_assignIn(load, { del }, options);
return load;
}
function del() {
const key = hash.apply(this, arguments);
cache.del(key);
}
const result = function () {
const args = vfs.apply(null, arguments);
const parameters = args.slice(0, -1);
const callback = args.slice(-1).pop();
const self = this;
var key;
if (bypass && bypass.apply(self, parameters)) {
return load.apply(self, args);
}
if (parameters.length === 0 && !hash) {
//the load function only receives callback.
key = '_';
} else {
key = hash.apply(self, parameters);
}
var fromCache = cache.get(key);
if (fromCache) {
if (clone) {
return callback.apply(null, [null].concat(fromCache).map(_cloneDeep));
}
return callback.apply(null, [null].concat(fromCache));
}
if (!loading.get(key)) {
loading.set(key, []);
load.apply(self, parameters.concat(function (err) {
const args = vfs.apply(null, arguments);
//we store the result only if the load didn't fail.
if (!err) {
const result = args.slice(1);
if (freeze) {
args.forEach(deepFreeze);
}
if (itemMaxAge) {
cache.set(key, result, itemMaxAge.apply(self, parameters.concat(result)));
} else {
cache.set(key, result);
}
}
//immediately call every other callback waiting
const waiting = loading.get(key).concat(callback);
loading.delete(key);
waiting.forEach(function (callback) {
if (clone) {
return callback.apply(null, args.map(_cloneDeep));
}
callback.apply(null, args);
});
/////////
}));
} else {
loading.get(key).push(callback);
}
};
result.keys = cache.keys.bind(cache);
_assignIn(result, { del }, options);
return result;
};
module.exports.sync = function (options) {
const cache = new LRU(_pick(options, lru_params));
const load = options.load;
const hash = options.hash;
const disable = options.disable;
const bypass = options.bypass;
const self = this;
const itemMaxAge = options.itemMaxAge;
if (disable) {
return load;
}
const result = function () {
var args = _toArray(arguments);
if (bypass && bypass.apply(self, arguments)) {
return load.apply(self, arguments);
}
var key = hash.apply(self, args);
var fromCache = cache.get(key);
if (fromCache) {
return fromCache;
}
const result = load.apply(self, args);
if (itemMaxAge) {
cache.set(key, result, itemMaxAge.apply(self, args.concat([ result ])));
} else {
cache.set(key, result);
}
return result;
};
result.keys = cache.keys.bind(cache);
return result;
};