MST

星途 面试题库

面试题:TypeScript泛型类在复杂场景下的应用与优化

假设你正在开发一个缓存系统,需要设计一个泛型类`Cache`,它可以缓存不同类型的数据。该类接收两个类型参数,一个是缓存数据的类型`T`,另一个是缓存键的类型`K`。要求实现以下功能:1. 提供`set`方法,用于将数据存储到缓存中,键值对为`(K, T)`;2. 提供`get`方法,根据键`K`获取缓存中的数据`T`;3. 实现缓存过期机制,在`set`方法中可以传入一个过期时间(以毫秒为单位),当调用`get`方法时,如果数据已过期,返回`null`。同时,为了优化内存使用,需要在数据过期后自动清理缓存。请给出高效且健壮的TypeScript代码实现,并简要说明设计思路和可能存在的性能瓶颈及优化方向。
37.0万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试
class Cache<T, K> {
    private cache: Map<K, { value: T; expiration: number }>;
    private timer: Map<K, NodeJS.Timeout>;

    constructor() {
        this.cache = new Map();
        this.timer = new Map();
    }

    set(key: K, value: T, expiration: number): void {
        const currentTime = Date.now();
        const expirationTime = currentTime + expiration;
        this.cache.set(key, { value, expiration: expirationTime });

        if (this.timer.has(key)) {
            clearTimeout(this.timer.get(key) as NodeJS.Timeout);
        }

        const timeout = setTimeout(() => {
            this.cache.delete(key);
            this.timer.delete(key);
        }, expiration);

        this.timer.set(key, timeout);
    }

    get(key: K): T | null {
        const cached = this.cache.get(key);
        if (cached) {
            const currentTime = Date.now();
            if (currentTime < cached.expiration) {
                return cached.value;
            } else {
                this.cache.delete(key);
                if (this.timer.has(key)) {
                    clearTimeout(this.timer.get(key) as NodeJS.Timeout);
                    this.timer.delete(key);
                }
                return null;
            }
        }
        return null;
    }
}

设计思路

  1. 数据存储:使用Map来存储键值对,这样可以方便地根据键获取值,并且Map的查找时间复杂度为O(1)。
  2. 过期机制:为每个缓存项记录过期时间,每次设置缓存时更新过期时间,并设置一个定时器,在过期时自动删除缓存项。
  3. 内存优化:通过定时器在数据过期后自动清理缓存,避免无效数据占用内存。

性能瓶颈及优化方向

  1. 性能瓶颈
    • 定时器管理:如果缓存项非常多,定时器的创建和管理可能会消耗大量资源,影响性能。
    • 过期检查:每次获取缓存时都检查过期时间,在高并发场景下可能会有性能问题。
  2. 优化方向
    • 定时器合并:可以考虑使用一个统一的定时器,定期检查所有缓存项的过期时间,而不是为每个缓存项创建单独的定时器。
    • 懒删除与定期清理:在获取缓存时不立即删除过期数据,而是标记为过期,然后通过一个后台任务定期清理过期数据,减少高并发场景下的性能开销。