Sunny-117 / js-challenges

✨✨✨ Challenge your JavaScript programming limits step by step
https://juejin.cn/column/7244788137410560055
2.02k stars 235 forks source link

系统设计题:缓存类 TipCache设计 #511

Open Sunny-117 opened 3 months ago

Sunny-117 commented 3 months ago

假设你有一个缓存类 TipCache,用于在内存中存储键值对。以下是该类的初始实现:

class TipCache {
    constructor() {
        this._cachePool = {};
    }

    set(key, value) {
        this._cachePool[key] = value;
    }

    get(key) {
        return this._cachePool[key];
    }
}

export default new TipCache();

任务1:基于上述 TipCache 类,请你完成以下功能:

任务2:为该缓存类增加以下高级功能:

任务3:编写单元测试,确保你的实现能够正确处理以下情况:

要求:

提示

Sunny-117 commented 3 months ago
class TipCache {
    constructor(maxSize = 5) {
        this._cachePool = new Map(); // 使用 Map 来维护顺序
        this._maxSize = maxSize;
    }

    _isExpired(entry) {
        if (entry.expiry && Date.now() > entry.expiry) {
            return true;
        }
        return false;
    }

    set(key, value, ttl = 0) {
        if (this._cachePool.has(key)) {
            // 删除旧的位置,重新插入新位置
            this._cachePool.delete(key);
        } else if (this._cachePool.size >= this._maxSize) {
            // 淘汰最久未使用的缓存项
            const oldestKey = this._cachePool.keys().next().value;
            this._cachePool.delete(oldestKey);
        }

        const expiry = ttl > 0 ? Date.now() + ttl : null;
        this._cachePool.set(key, { value, expiry });
    }

    get(key) {
        if (!this._cachePool.has(key)) {
            return null;
        }

        const entry = this._cachePool.get(key);
        if (this._isExpired(entry)) {
            // 过期处理
            this._cachePool.delete(key);
            return null;
        }

        // 每次访问都将缓存项移动到 Map 的尾部
        this._cachePool.delete(key);
        this._cachePool.set(key, entry);

        return entry.value;
    }

    delete(key) {
        return this._cachePool.delete(key);
    }

    has(key) {
        if (!this._cachePool.has(key)) {
            return false;
        }

        const entry = this._cachePool.get(key);
        if (this._isExpired(entry)) {
            // 过期处理
            this._cachePool.delete(key);
            return false;
        }

        return true;
    }

    size() {
        return this._cachePool.size;
    }
}

export default TipCache;