diff --git a/src/caches/ttl.ts b/src/caches/ttl.ts index 107abb1..39aa95a 100644 --- a/src/caches/ttl.ts +++ b/src/caches/ttl.ts @@ -1,84 +1,96 @@ -import { Cache } from './cache' -import { TTLParams, Keyable } from '../types' - -/** - * ### About - * This cache removes values based on TTL (Time-To-Live). - * - * If you store a key with a TTL of 1 second, that key will be removed after 1 second. - * - * ### Example - * ```typescript - * const cache = new TTLCache({maxsize: 2, ttl: 1000}) - * - * //store some keys - * - * //default ttl will be used (1000) - * cache['foo'] = 'bar' - * - * //custom ttl will be used (500) - * cache.set('bar', 'foo', 500) - * - * //store another key - * cache['baz'] = 'foo' - * //throws SizeError, you need to delete some key to store another key - * - * //will log: undefined - * setTimeout(() => console.log(cache['bar']), 1000) - * - * ``` - */ -export class TTLCache extends Cache { - protected _timeouts: Map - protected _defaultTTL?: number - - /** - * Creates a new TTLCache. - */ - constructor(params: TTLParams = {}){ - super({ - maxsize: params.maxsize, - useClones: params.useClones - }) - - this._timeouts = new Map() - if (params.ttl) { - this._defaultTTL = params.ttl - } - } - - set(key: Keyable, value: unknown, ttl = 0){ - super.set(key, value) - - if (this._timeouts.has(key)) { - clearTimeout( - this._timeouts.get(key) - ) - - this._timeouts.delete(key) - } - - if (ttl || this._defaultTTL){ - this._timeouts.set( - key, - setTimeout( - () => { - this.del(key) - this.emit('expired', key) - }, - ttl || this._defaultTTL - ) - ) - } - } - - del(key: Keyable){ - super.del(key) - if (this._timeouts.has(key)) { - clearTimeout( - this._timeouts.get(key) - ) - this._timeouts.delete(key) - } - } -} +import { Cache } from './cache' +import { TTLParams, Keyable } from '../types' + +/** + * ### About + * This cache removes values based on TTL (Time-To-Live). + * + * If you store a key with a TTL of 1 second, that key will be removed after 1 second. + * + * ### Example + * ```typescript + * const cache = new TTLCache({maxsize: 2, ttl: 1000}) + * + * //store some keys + * + * //default ttl will be used (1000) + * cache['foo'] = 'bar' + * + * //custom ttl will be used (500) + * cache.set('bar', 'foo', 500) + * + * //store another key + * cache['baz'] = 'foo' + * //throws SizeError, you need to delete some key to store another key + * + * //will log: undefined + * setTimeout(() => console.log(cache['bar']), 1000) + * + * ``` + */ +export class TTLCache extends Cache { + protected _timeouts: Map + protected _defaultTTL?: number + protected _checkInterval?: number + private _intervalId?: NodeJS.Timeout + + /** + * Creates a new TTLCache. + */ + constructor(params: TTLParams = {}){ + super({ + maxsize: params.maxsize, + useClones: params.useClones + }) + + this._timeouts = new Map() + this._checkInterval = params.checkPeriod ?? 60000 + if (params.ttl) { + this._defaultTTL = params.ttl + } + + setInterval(() => this._checkExpired(), this._checkInterval) + } + + set(key: Keyable, value: unknown, ttl = 0){ + super.set(key, value) + + if (this._timeouts.has(key)) { + this._timeouts.delete(key) + } + + if (ttl || this._defaultTTL){ + this._timeouts.set( + key, + Date.now() + (ttl ?? this._defaultTTL) + ) + } + } + + del(key: Keyable){ + super.del(key) + if (this._timeouts.has(key)) { + this._timeouts.delete(key) + } + } + + private _clearInterval() { + if (this._intervalId) { + clearInterval(this._intervalId) + } + } + + destroy() { + this._clearInterval() + } + + private _checkExpired() { + const now = Date.now() + for (const [key, expirationTime] of this._timeouts.entries()) { + if (expirationTime <= now) { + this.del(key) + this.emit('expired', key) + } + } + } +} diff --git a/src/types/params.ts b/src/types/params.ts index ca27304..f793de6 100644 --- a/src/types/params.ts +++ b/src/types/params.ts @@ -1,40 +1,46 @@ -export interface CacheParams { - /** - * Defines the maximum number of keys that will be stored. - * In some caches, this parameter is required; the default is `undefined`. - */ - maxsize?: number - - /** - * If true, a **deep copy** of all data will be created before storing. - * The default is `false`. - */ - useClones?: boolean -} - -export interface TTLParams extends CacheParams { - /** - * The **Time to Live** of the cache in **ms**. - * If you don't provide the `ttl` parameter in the `set` function, this `ttl` will be used. - * If not provided, the cache will not delete keys. - */ - ttl?: number -} - -export interface RRParams extends CacheParams { - /** - * Random logic for the deletion of keys in the cache. - * The default is `Math.floor(Math.random() * length)`. - */ - randomLogic?: (length: number) => number -} - -export type ParamsLike = CacheParams | TTLParams | RRParams - -export interface CachePoolParams { - /** - * Defines the maximum number of caches that will be stored. - * This parameter is optional; the default is `undefined`. - */ - maxsize?: number -} +export interface CacheParams { + /** + * Defines the maximum number of keys that will be stored. + * In some caches, this parameter is required; the default is `undefined`. + */ + maxsize?: number + + /** + * If true, a **deep copy** of all data will be created before storing. + * The default is `false`. + */ + useClones?: boolean +} + +export interface TTLParams extends CacheParams { + /** + * The **Time to Live** of the cache in **ms**. + * If you don't provide the `ttl` parameter in the `set` function, this `ttl` will be used. + * If not provided, the cache will not delete keys. + */ + ttl?: number + + /** + * The **Check Period** to verify if key is expired or not. + * **default:** 60000 - 1 minute + */ + checkPeriod?: number +} + +export interface RRParams extends CacheParams { + /** + * Random logic for the deletion of keys in the cache. + * The default is `Math.floor(Math.random() * length)`. + */ + randomLogic?: (length: number) => number +} + +export type ParamsLike = CacheParams | TTLParams | RRParams + +export interface CachePoolParams { + /** + * Defines the maximum number of caches that will be stored. + * This parameter is optional; the default is `undefined`. + */ + maxsize?: number +}