Cache / 缓存

在项目中,我们经常用到缓存的功能,并且可能要用到不同类型的缓存。框架通过 think-cache 扩展和对应的 Adapter 来操作缓存。

配置扩展和 Adapter

修改扩展配置文件 src/config/extend.js(多模块项目为 src/common/config/extend.js),添加下面的配置:

const cache = require('think-cache');
module.exports = [
  cache
]

修改 Adapter 配置文件 src/config/adapter.js(多模块项目为 src/common/config/adapter.js),添加下面的配置:

const fileCache = require('think-cache-file');

exports.cache = {
  type: 'file',
  common: {
    timeout: 24 * 60 * 60 * 1000 // 单位:毫秒
  },
  file: {
    handle: fileCache,
    cachePath: path.join(think.ROOT_PATH, 'runtime/cache'), // 缓存文件存放的路径
    pathDepth: 1,
    gcInterval: 24 * 60 * 60 * 1000 // 清理过期缓存定时时间
  }
}

支持的缓存类型列表见:https://github.com/thinkjs/think-awesome#cache

注入的方法

添加 think-cache 扩展后,会注入 think.cachectx.cachecontroller.cache 方法,其中 ctx.cache 和 controller.cache 都是 think.cache 方法的包装,会读取当前请求下对应的缓存配置。

获取缓存

module.exports = class extends think.Controller {
  // 获取缓存
  async indexAction() {
    const data = await this.cache('name');
  }
  // 指定缓存类型获取,从 redis 里获取缓存,需要配置对应的 adapter
  async index2Action() {
    const data = await this.cache('name', undefined, 'redis');
  }
}

操作缓存的时候一般都是先读取缓存,如果不存在,再从对应的地方获取然后再写入缓存,如果每次都这么操作会导致代码写起来很麻烦。支持 value 为函数的方式来读取缓存。

module.exports = class extends think.Controller {
  // 如果缓存存在,直接读取缓存
  // 如果缓存不存在,则执行 value 函数,然后将返回值设置到缓存中并返回。
  // 如果 value 函数里有异步操作,需要返回 Promise
  async indexAction() {
    const data = await this.cache('name', () => {
      return getDataFromApi();
    });
  }
}

注:禁止在获取 cache 的回调中再次获取同 name 的 cache 操作,否则会导致业务死锁,详见 thinkjs/thinkjs#1407

设置缓存

module.exports = class extends think.Controller {
  // 设置缓存
  async indexAction() {
     await this.cache('name', 'value');
  }
  // 设置缓存,切换类型
  async index2Action() {
    await this.cache('name', 'value', 'redis');
  }
  // 设置缓存,切换类型
  async index2Action() {
    await this.cache('name', 'value', {
      type: 'redis',
      redis: {
        timeout: 24 * 60 * 60 * 1000
      }
    });
  }
  // 设置缓存超时时间
  async index2Action() {
    await this.cache('name', 'value', {
        timeout: 24 * 60 * 60 * 1000
    });
  }
}

删除缓存

将缓存值设置为 null 为删除缓存。

module.exports = class extends think.Controller {
  // 删除缓存
  async indexAction() {
    await this.cache('name', null);
  }
  // 删除缓存,切换类型
  async index2Action() {
    await this.cache('name', null, 'redis');
  }
}

缓存 gc

有些缓存容器在设置值的时候可以设置超时时间,如:Memcache、Redis,这样数据会自动过期然后删除。但有些缓存容器是没有自动删除的功能的,如:File、Db 等,这个时候就需要处理缓存过期后的清理。

缓存过期清理添加了 gcInterval 配置用来配置清理的时间间隔,最小为一个小时。表示为:一个小时执行一次缓存容器的 gc 方法,具体的清理逻辑在缓存的 gc 方法中定义,由 think-gc 模块负责调度。

常见问题

数据可以缓存在 Node.js 的内存中么?

理论上是可以的,但并不建议这么做。当缓存数据量暴涨时会导致内存占用量过大,进而影响用户请求的处理,得不偿失。

如发现文档中的错误,请点击这里修改本文档,修改完成后请 pull request,我们会尽快合并、更新。