UNPKG

@newdash/newdash

Version:

javascript/typescript utility library

155 lines (154 loc) 4.08 kB
"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;