@newdash/newdash
Version:
javascript/typescript utility library
155 lines (154 loc) • 4.08 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TTLMap = void 0;
/**
* TTL (Time to Life) Map
*
* it will lazy remove values when perform operations
*
* @category Functional
* @since 5.18.0
*/
class TTLMap extends Map {
/**
* TTLMap (Time to Life) Map
*
* it will lazy remove values when perform operations
*
* @param defaultTTL time to live, in milliseconds, default value is 60 seconds
* @param cleanAfterOperation execute full clean after operations. default value is 100, it means, at least 100 operations performed, the TTL evict logic will be executed
*/
constructor(defaultTTL = 60 * 1000, cleanAfterOperation = 100) {
super();
this.defaultTTL = defaultTTL;
this.timeoutStorage = new Map();
if (cleanAfterOperation > 1) {
this.cleanAfterOperation = cleanAfterOperation;
}
this.operationCount = 0;
}
/**
* default TTL value in milliseconds
*/
defaultTTL;
cleanAfterOperation;
operationCount;
timeoutStorage;
timestamp() {
return Date.now();
}
/**
* _checkAndClean
*
* for the simple operations (set/get/delete/has), the clean operation will not execute every time
*/
_checkAndClean() {
if (this.operationCount++ > this.cleanAfterOperation) {
this.operationCount = 0;
this.cleanTimeoutItems();
}
}
/**
* set value
*
* @param k key
* @param v value
* @param ttl time to live, in milliseconds, if undefined, will use instance level defaultTTL
* @returns
*/
set(k, v, ttl = this.defaultTTL) {
const expireTime = this.timestamp() + ttl - 1; // sub 1 to fix very accurate wait
this._checkAndClean();
super.set(k, v);
this.timeoutStorage.set(k, expireTime); // refresh timeout
return this;
}
has(k) {
this._checkAndClean();
let rt = false;
if (super.has(k)) {
const isTimeout = this.checkTimeout(k);
if (isTimeout) {
rt = false;
}
else {
rt = true;
}
}
return rt;
}
get(k) {
this._checkAndClean();
let rt = undefined;
if (super.has(k)) {
const isTimeout = this.checkTimeout(k);
if (isTimeout) {
rt = undefined;
}
else {
rt = super.get(k);
}
}
return rt;
}
delete(k) {
this._checkAndClean();
const rt = super.delete(k);
this.timeoutStorage.delete(k);
return rt;
}
clear() {
super.clear();
this.timeoutStorage.clear();
this.operationCount = 0;
}
/**
* return true if timeout
*
* @param k
*/
checkTimeout(k, currentTimeStamp = this.timestamp()) {
const isTimeout = this.getTimeout(k) < currentTimeStamp;
if (isTimeout) {
super.delete(k);
this.timeoutStorage.delete(k);
}
return isTimeout;
}
getTimeout(k) {
if (this.timeoutStorage.has(k)) {
return this.timeoutStorage.get(k);
}
return 0;
}
/**
* manually directly clean all timeout items
*/
cleanTimeoutItems() {
const current = this.timestamp();
super.forEach((_, key) => { this.checkTimeout(key, current); });
}
entries() {
this.cleanTimeoutItems();
return super.entries();
}
keys() {
this.cleanTimeoutItems();
return super.keys();
}
values() {
this.cleanTimeoutItems();
return super.values();
}
forEach(callbackfn, thisArg) {
this.cleanTimeoutItems();
return super.forEach(callbackfn, thisArg);
}
get size() {
this.cleanTimeoutItems();
// @ts-ignore
return super.size;
}
}
exports.TTLMap = TTLMap;
exports.default = TTLMap;