需求:
请求接口之后, 缓存当前接口的数据, 下次请求同一接口时拿缓存数据, 不再重新请求
添加缓存失效时间
cache 使用 map 来实现
ES6 模块与 CommonJS 模块的差异
CommonJS 模块输出的是一个值的拷贝, ES6 模块输出的是值的引用.
CommonJS 模块是运行时加载, ES6 模块是编译时输出接口.
因为 esm 输出的是值的引用, 直接就是单例模式了
详细 https://maninboat.gitbooks.io/you-dont-know-js-es6/content/ch3.3.html
export let cache = new Cache()
版本 1
思路:
在 vuex 注册插件, 插件会在每次 mutations 提交之后, 判断要不要写入 cache
在提交 actions 的时候判断是否有 cache, 有就拿 cache 里面的数据, 然后把数据 commit 给 mutataios
注意: 在插件里面获取的 mutations-type 是包含命名空间的, 而在 actions 里面则是没有命名空间, 需要补全. /mutation-types.js
- /**
- * 需要缓存的数据会在 mutations-type 后面添加 - CACHED
- */
- export const SET_HOME_INDEX = 'SET_HOME_INDEX-CACHED'
- /modules/home/index.js
- const actions = {
- /**
- * @description 如果有缓存, 就返回把缓存的数据, 传入 mutations,
- * 没有缓存就从接口拿数据, 存入缓存, 把数据传入 mutations
- */
- async fetchAction ({commit}, {mutationType, fetchData, oPayload}) {
- // vuex 开启了命名空间, 所这里从 cachekey 要把命名空间前缀 + type + 把 payload 格式化成 JSON
- const cacheKey = NAMESPACE + mutationType + JSON.stringify(oPayload)
- const cacheResponse = cache.get(cacheKey || '')
- if (!cacheResponse) {
- const [err, response] = await fetchData()
- if (err) {
- console.error(err, 'error in fetchAction')
- return false
- }
- commit(mutationType, {response: response, oPayload})
- } else {
- console.log('已经进入缓存取数据!!!')
- commit(mutationType, {response: cacheResponse, oPayload})
- }
- },
- loadHomeData ({ dispatch, commit }) {
- dispatch(
- 'fetchAction',
- {
- mutationType: SET_HOME_INDEX,
- fetchData: api.index,
- }
- )
- }
- }
- const mutations = {
- [SET_HOME_INDEX] (state, {response, oPayload}) {},
- }
- const state = {
- indexData: {}
- }
- export default {
- namespaced: NAMESPACED,
- actions,
- state,
- getters,
- mutations
- }
编写插件, 在这里拦截 mutations, 判断是否要缓存
- /plugin/cache.js
- import cache from 'src/store/util/CacheOfStore'
- // import {strOfPayloadQuery} from 'src/store/util/index'
- /**
- * 在每次 mutations 提交之后, 把 mutations-type 后面有 CACHED 标志的数据存入缓存,
- * 现在 key 值是 mutations-type
- * 问题:
- * 没办法区分不同参数 query 的请求,
- *
- * 方法 1: 用每个 mutations-type + payload 的 json 格式为 key 来缓存数据
- */
- function cachePlugin () {
- return store => {
- store.subscribe(({ type, payload }, state) => {
- // 需要缓存的数据会在 mutations-type 后面添加 CACHED
- const needCache = type.split('-').pop() === 'CACHED'
- if (needCache) {
- // 这里的 type 会自动加入命名空间所以 cacheKey = type + 把 payload 格式化成 JSON
- const cacheKey = type + JSON.stringify(payload && payload.oPayload)
- const cacheResponse = cache.get(cacheKey)
- // 如果没有缓存就存入缓存
- if (!cacheResponse) {
- cache.set(cacheKey, payload.response)
- }
- }
- console.log(cache)
- })
- }
- }
- const plugin = cachePlugin()
- export default plugin
- store/index.js
- import Vue from 'vue'
- import Vuex from 'vuex'
- import home from './modules/home'
- import cachePlugin from './plugins/cache'
- Vue.use(Vuex)
- const store = new Vuex.Store({
- modules: {
- home,
- editActivity,
- editGuide
- }
- plugins: [cachePlugin]
- })
- export default store
版本 2
思路:
直接包装 fetch 函数, 在里面里面判断是否需要缓存, 缓存是否超时.
优化点:
把原本分散的 cache 操作统一放入到 fetch
减少了对命名空间的操作
添加了缓存有效时间
- /actions.js
- const actions = {
- async loadHomeData ({ dispatch, commit }, oPayload) {
- commit(SET_HOME_LOADSTATUS)
- const [err, response] = await fetchOrCache({
- api: api.index,
- queryArr: oPayload.queryArr,
- mutationType: SET_HOME_INDEX
- })
- if (err) {
- console.log(err, 'loadHomeData error')
- return [err, response]
- }
- commit(SET_HOME_INDEX, { response })
- return [err, response]
- }
- }
/ 在 fetchOrCache 判断是需要缓存, 还是请求接口
- /**
- * 用这个函数就说明是需要进入缓存
- * @param {*} api 请求的接口
- * @param {*} queryArr 请求的参数
- * @param {*} mutationType 传入 mutationType 作为 cache 的 key 值
- */
- export async function fetchOrCache ({api, queryArr, mutationType, diff}) {
- // 这里是请求接口
- const fetch = httpGet(api, queryArr)
- const cachekey = `${mutationType}:${JSON.stringify(queryArr)}`
- if (cache.has(cachekey)) {
- const obj = cache.get(cachekey)
- if (cacheFresh(obj.cacheTimestemp, diff)) {
- return cloneDeep(obj)
- } else {
- // 超时就删除
- cache.delete(cachekey)
- }
- }
- // 不取缓存的处理
- let response = await fetch()
- // 时间戳绑定在数组的属性上
- response.cacheTimestemp = Date.now()
- cache.set(cachekey, response)
- // 返回 cloneDeep 的对象
- return cloneDeep(response)
- }
- /**
- * 判断缓存是否失效
- * @param {*} diff 失效时间差, 默认 15 分钟 = 900s
- */
- const cacheFresh = (cacheTimestemp, diff = 900) => {
- if (cacheTimestemp) {
- return ((Date.now() - cacheTimestemp) / 1000) <= diff
- } else {
- return true
- }
- }
来源: https://juejin.im/entry/5b0cc9ddf265da08e916e664