缓存 
临时存储不经常变化的数据或者热数据
安装 
pnpm add @aomex/cache使用 
内置一个内存适配器,适合在开发和测试阶段使用
import { Caching, memoryAdapter } from '@aomex/cache';
export const memoryCache = new Caching(memoryAdapter());数据类型 
js内置的基础类型和复杂类型数据,均可存储
export type Types =
  | string
  | number
  | object
  | boolean
  | bigint
  | Map
  | Set
  | Date;通用方法 
get() 
签名:<T>(key: string, defaultValue: T): Promise<T><T extends Types>(key: string): Promise<T | null>
获取缓存。如果未找到缓存并且未提供默认值,则返回null
set() 
签名:(key: string, value: Types, durationMS?: number) => Promise<boolean>
设置缓存。可以指定过期时间(毫秒)
setNX() 
签名:(key: string, value: Types, durationMs?: number): Promise<boolean>
设置缓存。如果缓存已经存在,则设置失败,返回false
await cache.setNX('foo', 'bar'); // true
await cache.setNX('foo', 'baz'); // falseleftPush() 
签名:(key: string, ...values: Types[]): Promise<boolean>
将一个或多个值按顺序插入到列表头部。当 key 存在但不是列表类型时,返回一个错误
await cache.leftPush('foo', 'a'); // ['a']
await cache.leftPush('foo', 'b', 'c'); // ['b', 'c', 'a']rightPop() 
签名:<T extends Types>(key: string): Promise<T | null>
移除列表的最后一个元素,返回值为被移除的元素
increment() 
签名:(key: string): Promise<number>
将key中储存的数字值增一。如果key不存在,那么key的值会先被初始化为0,然后再执行操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误
await cache.increment('foo'); // 1
await cache.increment('foo'); // 2
await cache.increment('foo'); // 3decrement() 
签名:(key: string): Promise<number>
将key中储存的数字值减一。如果key不存在,那么key的值会先被初始化为0,然后再执行操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
expire() 
签名:(key: string, durationMs: number): Promise<boolean>
重新设置缓存时间。如果key不存在,则返回false
exists() 
签名:(key: string): Promise<boolean>
查看缓存是否存在
ttl() 
签名:(key: string): Promise<number>
检测缓存的剩余生存时间(Time to live)
- 不存在则返回
-2 - 未设置过期时间则返回
-1 - 已设置过期时间则返回剩余时间,单位毫秒
 
await cache.ttl('foo'); // -2
await cache.set('foo', 'bar');
await cache.ttl('foo'); // -1
await cache.expire('foo', 60000);
await cache.ttl('foo'); // 59000delete() 
签名:(key: string): Promise<boolean>
删除指定缓存
deleteAll() 
签名:(): Promise<boolean>
删除所有缓存
装饰器 
想象一下,你是否经常写这种代码,先判断缓存是否存在,不存在则获取,然后保存缓存。
class MyClass {
  async getMyData(id: number) {
    const key = `my_key_${id}`;
    let data = await cache.get(key);
    if (!data) {
      data = await ... // 业务逻辑在这里
      await cache.set(key, data, 3600_000);
    }
    return data;
  }
}这种写法有以下几个方面的缺点:
- 过于模板化,浪费时间
 - 模板化不利于阅读
 - 拼接key有点繁琐
 - 并发时,缓存未命中的情况下,逻辑被执行多次
 
此时,装饰器方案可以很好地解决这些问题
class MyClass {
  @cache.decorate({ duration: 3600_000 })
  async getMyData(id: number) {
    const data = await ... // 业务逻辑在这里
    return data;
  }
}是了,带来一种清爽的感觉!缓存逻辑与业务分离,书写方便,利于阅读,还能自动管理key,重点是并发时只处理一次逻辑。
如果你想手动管理key,那也是没问题的
class MyClass {
  @cache.decorate({
    // 这里id的类型会自动推导为number类型
    key: (id) => `my_key_${id}`,
    duration: 3600_000,
  })
  async getMyData(id: number) {
    const data = await ... // 业务逻辑在这里
    return data;
  }
}如果key不需要参数,也可以大胆地使用常量(这意味着总是只有一个缓存)
class MyClass {
  @cache.decorate({ key: 'my_key', duration: 3600_000 })
  async getMyData(id: number) {
    const data = await ... // 业务逻辑在这里
    return data;
  }
}redis适配器 
import { Caching } from '@aomex/cache';
import { redisAdapter } from '@aomex/cache-redis-adapter';
export const redisCache = new Caching(
  redisAdapter({
    host: '',
    password: '',
    port: 6379,
  }),
);