MST
星途 面试题库

面试题:TypeScript 封装 RESTful API 客户端如何实现高效的缓存机制

在使用 TypeScript 封装 RESTful API 客户端时,要求实现一个高效的缓存机制。阐述你的设计思路,包括如何确定缓存策略(如缓存时间、缓存更新策略等),如何使用泛型来使缓存机制更通用,以及在高并发场景下如何保证缓存的一致性。请提供核心的 TypeScript 代码实现。
42.2万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 缓存策略
    • 缓存时间:可以为每个缓存项设置一个过期时间(TTL,Time To Live)。当缓存项被访问时,检查其是否过期,若过期则从缓存中移除。
    • 缓存更新策略:常见策略有写后失效(Write - Through)、写前失效(Write - Behind Caching)和读写失效(Read - Write - Through)。写后失效即在数据更新后使相关缓存失效;写前失效是在更新数据前先失效缓存;读写失效则是读写操作都检查并更新缓存。在 RESTful API 客户端场景下,写后失效较为常用,因为简单直接,能保证数据一致性。
  2. 使用泛型: 通过泛型可以使缓存机制适用于不同类型的 API 响应数据。定义缓存类或函数时,使用泛型参数表示缓存数据的类型,这样无论 API 返回的数据是简单对象、数组还是其他复杂类型,缓存机制都能适配。
  3. 高并发场景下缓存一致性
    • 使用互斥锁(如 JavaScript 中的 async/await 结合 Promise 实现)来防止多个并发请求同时更新或读取缓存。在读取缓存前,先获取锁,操作完成后释放锁。
    • 采用分布式缓存(如 Redis),利用其原子操作特性,如 SETNX(Set if Not eXists)来保证在分布式环境下缓存的一致性。

核心 TypeScript 代码实现

class Cache<T> {
    private cache: Map<string, { value: T; expiration: number }> = new Map();
    private mutex: boolean = false;

    constructor(private ttl: number) {}

    async get(key: string): Promise<T | null> {
        while (this.mutex) {
            await new Promise(resolve => setTimeout(resolve, 100));
        }
        this.mutex = true;
        try {
            const cached = this.cache.get(key);
            if (cached && cached.expiration > Date.now()) {
                return cached.value;
            }
            return null;
        } finally {
            this.mutex = false;
        }
    }

    set(key: string, value: T) {
        const expiration = Date.now() + this.ttl;
        this.cache.set(key, { value, expiration });
    }

    invalidate(key: string) {
        this.cache.delete(key);
    }
}

// 使用示例
async function fetchData<T>(cache: Cache<T>, key: string, apiCall: () => Promise<T>): Promise<T> {
    let data = await cache.get(key);
    if (!data) {
        data = await apiCall();
        cache.set(key, data);
    }
    return data;
}

在上述代码中:

  • Cache 类封装了缓存逻辑,使用 Map 来存储缓存数据,每个缓存项包含数据值和过期时间。
  • get 方法使用互斥锁来处理高并发读取,确保同一时间只有一个请求能读取缓存。
  • set 方法设置缓存项,并根据 TTL 设置过期时间。
  • invalidate 方法用于使指定缓存项失效。
  • fetchData 函数展示了如何结合缓存机制进行 API 数据获取,先尝试从缓存读取,若缓存不存在则调用 API 获取数据并更新缓存。