fast-ttl-cache 0.0.4 → 0.0.6
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 +9 -5
- package/dist/index.js +149 -0
- package/{index.mjs → dist/index.mjs} +37 -44
- package/package.json +17 -4
- package/test.mjs +0 -36
package/README.md
CHANGED
|
@@ -37,20 +37,24 @@ cache.size; // return 0
|
|
|
37
37
|
## API
|
|
38
38
|
```FastTTLCache(options) consturctor```
|
|
39
39
|
|
|
40
|
-
options.ttl
|
|
41
|
-
options.capacity
|
|
40
|
+
- ```options.ttl```: number of millseconds, defaults to Infinity
|
|
41
|
+
- ```options.capacity```: number of max capacity, defaults to Infinity
|
|
42
42
|
|
|
43
43
|
```FastTTLCache.prototype.put(key, value)```
|
|
44
44
|
|
|
45
|
-
Add or update the value into cache with key and timestamp.
|
|
45
|
+
- Add or update the value into cache with key and timestamp.
|
|
46
46
|
|
|
47
47
|
```FastTTLCache.prototype.get(key)```
|
|
48
48
|
|
|
49
|
-
Get the value of the key from cache, return null if the key is not exists or has been expired.
|
|
49
|
+
- Get the value of the key from cache, return null if the key is not exists or has been expired.
|
|
50
|
+
|
|
51
|
+
```FastTTLCache.prototype.del(key)```
|
|
52
|
+
|
|
53
|
+
- delete key and it's value from cache, return false if the key is not exists, otherwise return true.
|
|
50
54
|
|
|
51
55
|
```FastTTLCache.prototype.size```
|
|
52
56
|
|
|
53
|
-
return the current size of cache.
|
|
57
|
+
- return the current size of cache, note because of the lazy deletion mechanism, it's not the exact number of cache items that are valid.
|
|
54
58
|
|
|
55
59
|
## License
|
|
56
60
|
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/index.mjs
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
|
+
default: () => TTLCache
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
|
+
var TTLCache = class {
|
|
26
|
+
/**
|
|
27
|
+
* 构造函数
|
|
28
|
+
* @param options 配置选项,包含ttl(过期时间)和capacity(容量)
|
|
29
|
+
*/
|
|
30
|
+
constructor(options = {}) {
|
|
31
|
+
this.ttl = options.ttl || Infinity;
|
|
32
|
+
this.capacity = options.capacity || Infinity;
|
|
33
|
+
this.store = /* @__PURE__ */ new Map();
|
|
34
|
+
this.head = this.tail = null;
|
|
35
|
+
this.size = 0;
|
|
36
|
+
Object.defineProperties(this, {
|
|
37
|
+
size: {
|
|
38
|
+
get() {
|
|
39
|
+
return this.store.size;
|
|
40
|
+
},
|
|
41
|
+
configurable: false
|
|
42
|
+
},
|
|
43
|
+
store: {
|
|
44
|
+
configurable: false,
|
|
45
|
+
enumerable: false,
|
|
46
|
+
writable: false
|
|
47
|
+
},
|
|
48
|
+
head: {
|
|
49
|
+
configurable: false,
|
|
50
|
+
enumerable: false
|
|
51
|
+
},
|
|
52
|
+
tail: {
|
|
53
|
+
configurable: false,
|
|
54
|
+
enumerable: false
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 获取缓存,惰性删除
|
|
60
|
+
* @param key 缓存键
|
|
61
|
+
* @returns 如果缓存存在且未过期返回值,否则返回null
|
|
62
|
+
*/
|
|
63
|
+
get(key) {
|
|
64
|
+
const item = this.store.get(key);
|
|
65
|
+
if (!item) return null;
|
|
66
|
+
if (Date.now() - item.time > this.ttl) {
|
|
67
|
+
this.del(key);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return item.value;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 设置缓存,包含已存在或新增
|
|
74
|
+
* @param key 缓存键
|
|
75
|
+
* @param value 缓存值
|
|
76
|
+
*/
|
|
77
|
+
put(key, value) {
|
|
78
|
+
if (this.size === 0) {
|
|
79
|
+
this.store.set(key, {
|
|
80
|
+
key,
|
|
81
|
+
value,
|
|
82
|
+
pre: null,
|
|
83
|
+
next: null,
|
|
84
|
+
time: Date.now()
|
|
85
|
+
});
|
|
86
|
+
this.head = this.tail = key;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (this.store.has(key)) {
|
|
90
|
+
const curItem = this.store.get(key);
|
|
91
|
+
curItem.value = value;
|
|
92
|
+
curItem.time = Date.now();
|
|
93
|
+
this.moveToTail(key);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const curTail = this.store.get(this.tail);
|
|
97
|
+
const newItem = {
|
|
98
|
+
key,
|
|
99
|
+
value,
|
|
100
|
+
pre: curTail,
|
|
101
|
+
next: null,
|
|
102
|
+
time: Date.now()
|
|
103
|
+
};
|
|
104
|
+
curTail.next = newItem;
|
|
105
|
+
this.store.set(key, newItem);
|
|
106
|
+
this.tail = key;
|
|
107
|
+
if (this.size > this.capacity) {
|
|
108
|
+
this.del(this.head);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 移除节点
|
|
113
|
+
* @param key
|
|
114
|
+
*/
|
|
115
|
+
del(key) {
|
|
116
|
+
if (!this.store.has(key)) return false;
|
|
117
|
+
const curItem = this.store.get(key);
|
|
118
|
+
if (this.size === 1) {
|
|
119
|
+
this.head = this.tail = null;
|
|
120
|
+
} else if (this.head === key) {
|
|
121
|
+
this.head = curItem.next.key;
|
|
122
|
+
curItem.next.pre = null;
|
|
123
|
+
} else if (this.tail === key) {
|
|
124
|
+
this.tail = curItem.pre.key;
|
|
125
|
+
curItem.pre.next = null;
|
|
126
|
+
} else {
|
|
127
|
+
curItem.pre.next = curItem.next;
|
|
128
|
+
curItem.next.pre = curItem.pre;
|
|
129
|
+
}
|
|
130
|
+
this.store.delete(key);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 将节点移动到队尾,队尾的节点一定是最后一个更新的
|
|
135
|
+
* @param key
|
|
136
|
+
*/
|
|
137
|
+
moveToTail(key) {
|
|
138
|
+
if (!this.store.has(key)) return;
|
|
139
|
+
if (this.tail === key) return;
|
|
140
|
+
const curItem = this.store.get(key);
|
|
141
|
+
this.del(key);
|
|
142
|
+
const curTail = this.store.get(this.tail);
|
|
143
|
+
curTail.next = curItem;
|
|
144
|
+
curItem.pre = curTail;
|
|
145
|
+
curItem.next = null;
|
|
146
|
+
this.tail = key;
|
|
147
|
+
this.store.set(key, curItem);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// src/index.mjs
|
|
2
|
+
var TTLCache = class {
|
|
3
3
|
/**
|
|
4
4
|
* 构造函数
|
|
5
5
|
* @param options 配置选项,包含ttl(过期时间)和capacity(容量)
|
|
@@ -7,17 +7,31 @@ export default class TTLCache {
|
|
|
7
7
|
constructor(options = {}) {
|
|
8
8
|
this.ttl = options.ttl || Infinity;
|
|
9
9
|
this.capacity = options.capacity || Infinity;
|
|
10
|
-
this.store = new Map();
|
|
10
|
+
this.store = /* @__PURE__ */ new Map();
|
|
11
11
|
this.head = this.tail = null;
|
|
12
12
|
this.size = 0;
|
|
13
|
-
Object.
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
Object.defineProperties(this, {
|
|
14
|
+
size: {
|
|
15
|
+
get() {
|
|
16
|
+
return this.store.size;
|
|
17
|
+
},
|
|
18
|
+
configurable: false
|
|
16
19
|
},
|
|
17
|
-
|
|
20
|
+
store: {
|
|
21
|
+
configurable: false,
|
|
22
|
+
enumerable: false,
|
|
23
|
+
writable: false
|
|
24
|
+
},
|
|
25
|
+
head: {
|
|
26
|
+
configurable: false,
|
|
27
|
+
enumerable: false
|
|
28
|
+
},
|
|
29
|
+
tail: {
|
|
30
|
+
configurable: false,
|
|
31
|
+
enumerable: false
|
|
32
|
+
}
|
|
18
33
|
});
|
|
19
34
|
}
|
|
20
|
-
|
|
21
35
|
/**
|
|
22
36
|
* 获取缓存,惰性删除
|
|
23
37
|
* @param key 缓存键
|
|
@@ -26,86 +40,72 @@ export default class TTLCache {
|
|
|
26
40
|
get(key) {
|
|
27
41
|
const item = this.store.get(key);
|
|
28
42
|
if (!item) return null;
|
|
29
|
-
// 检查缓存是否过期,过期则删除
|
|
30
43
|
if (Date.now() - item.time > this.ttl) {
|
|
31
|
-
this.
|
|
44
|
+
this.del(key);
|
|
32
45
|
return null;
|
|
33
46
|
}
|
|
34
47
|
return item.value;
|
|
35
48
|
}
|
|
36
|
-
|
|
37
49
|
/**
|
|
38
50
|
* 设置缓存,包含已存在或新增
|
|
39
51
|
* @param key 缓存键
|
|
40
52
|
* @param value 缓存值
|
|
41
53
|
*/
|
|
42
54
|
put(key, value) {
|
|
43
|
-
// 缓存为空时的处理
|
|
44
55
|
if (this.size === 0) {
|
|
45
56
|
this.store.set(key, {
|
|
46
57
|
key,
|
|
47
58
|
value,
|
|
48
59
|
pre: null,
|
|
49
60
|
next: null,
|
|
50
|
-
time: Date.now()
|
|
61
|
+
time: Date.now()
|
|
51
62
|
});
|
|
52
63
|
this.head = this.tail = key;
|
|
53
64
|
return;
|
|
54
65
|
}
|
|
55
|
-
|
|
56
|
-
// 数据已存在时的处理
|
|
57
66
|
if (this.store.has(key)) {
|
|
58
|
-
// 更新节点的值和时间戳
|
|
59
67
|
const curItem = this.store.get(key);
|
|
60
68
|
curItem.value = value;
|
|
61
69
|
curItem.time = Date.now();
|
|
62
|
-
|
|
63
|
-
// 移动到尾部
|
|
64
70
|
this.moveToTail(key);
|
|
65
71
|
return;
|
|
66
72
|
}
|
|
67
|
-
|
|
68
|
-
// 新数据插入尾部
|
|
69
73
|
const curTail = this.store.get(this.tail);
|
|
70
74
|
const newItem = {
|
|
71
75
|
key,
|
|
72
76
|
value,
|
|
73
77
|
pre: curTail,
|
|
74
78
|
next: null,
|
|
75
|
-
time: Date.now()
|
|
79
|
+
time: Date.now()
|
|
76
80
|
};
|
|
77
81
|
curTail.next = newItem;
|
|
78
82
|
this.store.set(key, newItem);
|
|
79
83
|
this.tail = key;
|
|
80
|
-
|
|
81
|
-
// 超出容量时,删除最久未更新的节点(头部节点)
|
|
82
84
|
if (this.size > this.capacity) {
|
|
83
|
-
this.
|
|
85
|
+
this.del(this.head);
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
|
-
|
|
87
88
|
/**
|
|
88
89
|
* 移除节点
|
|
89
90
|
* @param key
|
|
90
91
|
*/
|
|
91
|
-
|
|
92
|
-
if (!this.store.has(key)) return;
|
|
93
|
-
// 获取当前节点
|
|
92
|
+
del(key) {
|
|
93
|
+
if (!this.store.has(key)) return false;
|
|
94
94
|
const curItem = this.store.get(key);
|
|
95
|
-
if (this.size === 1) {
|
|
95
|
+
if (this.size === 1) {
|
|
96
96
|
this.head = this.tail = null;
|
|
97
|
-
} else if (this.head === key) {
|
|
97
|
+
} else if (this.head === key) {
|
|
98
98
|
this.head = curItem.next.key;
|
|
99
99
|
curItem.next.pre = null;
|
|
100
|
-
} else if (this.tail === key) {
|
|
100
|
+
} else if (this.tail === key) {
|
|
101
101
|
this.tail = curItem.pre.key;
|
|
102
102
|
curItem.pre.next = null;
|
|
103
|
-
} else {
|
|
103
|
+
} else {
|
|
104
104
|
curItem.pre.next = curItem.next;
|
|
105
105
|
curItem.next.pre = curItem.pre;
|
|
106
106
|
}
|
|
107
|
-
// 从 store 里删除节点
|
|
108
107
|
this.store.delete(key);
|
|
108
|
+
return true;
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
111
|
* 将节点移动到队尾,队尾的节点一定是最后一个更新的
|
|
@@ -113,24 +113,17 @@ export default class TTLCache {
|
|
|
113
113
|
*/
|
|
114
114
|
moveToTail(key) {
|
|
115
115
|
if (!this.store.has(key)) return;
|
|
116
|
-
// 当前已经是尾部节点了
|
|
117
116
|
if (this.tail === key) return;
|
|
118
|
-
|
|
119
|
-
// 获取当前节点
|
|
120
117
|
const curItem = this.store.get(key);
|
|
121
|
-
|
|
122
|
-
this.removeItem(key);
|
|
123
|
-
|
|
124
|
-
// 获取队尾节点
|
|
118
|
+
this.del(key);
|
|
125
119
|
const curTail = this.store.get(this.tail);
|
|
126
|
-
|
|
127
|
-
// 将节点移动到队尾
|
|
128
120
|
curTail.next = curItem;
|
|
129
121
|
curItem.pre = curTail;
|
|
130
122
|
curItem.next = null;
|
|
131
123
|
this.tail = key;
|
|
132
|
-
// 设置缓存
|
|
133
124
|
this.store.set(key, curItem);
|
|
134
125
|
}
|
|
135
126
|
};
|
|
136
|
-
|
|
127
|
+
export {
|
|
128
|
+
TTLCache as default
|
|
129
|
+
};
|
package/package.json
CHANGED
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-ttl-cache",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "ttl cache with capacity support use no timer",
|
|
5
|
-
"
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
6
7
|
"exports": {
|
|
7
8
|
".": {
|
|
8
|
-
"
|
|
9
|
+
"require": "./dist/index.js",
|
|
10
|
+
"import": "./dist/index.mjs"
|
|
9
11
|
}
|
|
10
12
|
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup src/ --format cjs,esm",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
11
17
|
"repository": {
|
|
12
18
|
"type": "git",
|
|
13
19
|
"url": "https://github.com/xincici/fast-ttl-cache"
|
|
14
20
|
},
|
|
15
21
|
"author": "linye<llxy8687@foxmail.com>",
|
|
16
|
-
"license": "MIT"
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"tsup": "^8.5.0",
|
|
25
|
+
"typescript": "^5.9.2"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist/"
|
|
29
|
+
]
|
|
17
30
|
}
|
package/test.mjs
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import TTLCache from './index.mjs';
|
|
3
|
-
|
|
4
|
-
const sleep = ms => new Promise(res => setTimeout(res, ms));
|
|
5
|
-
|
|
6
|
-
const c = new TTLCache({
|
|
7
|
-
ttl: 1000,
|
|
8
|
-
capacity: 3,
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
c.put('a', 'aaaa');
|
|
12
|
-
c.put('a', 'aaaaaa');
|
|
13
|
-
|
|
14
|
-
await sleep(200);
|
|
15
|
-
c.put('b', 'bbbb');
|
|
16
|
-
|
|
17
|
-
await sleep(500);
|
|
18
|
-
c.put('c', 'cccc');
|
|
19
|
-
|
|
20
|
-
await sleep(500);
|
|
21
|
-
c.put('b', 'bbbbbb');
|
|
22
|
-
|
|
23
|
-
await sleep(600);
|
|
24
|
-
c.put('d', 'dddd');
|
|
25
|
-
|
|
26
|
-
console.log('b', c.get('b'));
|
|
27
|
-
|
|
28
|
-
await sleep(600);
|
|
29
|
-
c.put('e', 'eeee');
|
|
30
|
-
|
|
31
|
-
console.log(c);
|
|
32
|
-
console.log(c.store.keys());
|
|
33
|
-
console.log('b', c.get('b'));
|
|
34
|
-
console.log('c', c.get('c'));
|
|
35
|
-
console.log('a', c.get('a'));
|
|
36
|
-
console.log('e', c.get('e'));
|