/**
* @description factory function of cache
* @param {object} cache
* @param {number} lifeCycle
*/
import { jsonStringify, safeJsonParse } from './str.js';
import { isObject } from "./typer";
import {getter} from "./obj.js";
import {getWindow} from "./env.js";
/**
* @typedef {Object} CacheObject - A cache object with methods to manage cache data.
* @property {object} cache - The cache object that holds the cache data.
* @property {function} getData - Returns the cache data.
* @property {function} containsKey - Checks if the cache contains a specific key.
* @property {function} getCache - Retrieves the value associated with a specific key from the cache.
* @property {function} setCache - Sets a value in the cache for a specific key.
* @property {function} clearCache - Clears the entire cache.
* @property {function} init - Initializes the cache with a new cache object.
* @property {function} clearExpire - Clears expired cache entries based on the defined life cycle.
*/
/**
* @description create object to manage cache
* @param {object} [cache={}] cache data object
* @param {number} [lifeCycle=0] cache time ms
* @returns {CacheObject}
*/
export function CacheFactory(cache, lifeCycle) {
return {
cache: cache,
getData() {
return this.cache;
},
containsKey(key){
return this.cache.hasOwnProperty(key);
},
getCache(key) {
this.clearExpire();
if (this.cache[key]) {
// console.log('hit cache', key);
return this.cache[key].value;
} else {
// console.log('init ');
return {}.value;
} // return (this.cache[key] || {}).value;
},
setCache(key, value) {
this.clearExpire();
this.cache[key] = {
timestamp: new Date().getTime(),
value: value,
};
},
clearCache() {
Object.keys(this.cache).forEach(key => {
delete this.cache[key];
});
},
init(newCache) {
Object.assign(this.cache, newCache);
},
clearExpire() {
let now = new Date().getTime();
Object.keys(this.cache).forEach(key => {
let info = this.cache[key] || {};
if (!info.timestamp) {
delete this.cache[key];
return;
}
let oldTimeStamp = info.timestamp;
if (now - oldTimeStamp > lifeCycle) {
delete this.cache[key];
}
});
},
};
}
/**
* @typedef {Object} DiskCache
* @property {CacheObject} Cacher
* @property {Function} getCache
* @property {Function} setCache
* @property {Function} getTotalData
* @property {Function} reportError
* @property {Function} clearCache
*/
/**
* @description create object to manage cache by localStorage
* @param {string} DISK_CACHE_KEY - cache group key
* @param {number|Function} [lifeCycle=0] cache time
* @returns {CacheObject | DiskCache} 。
*/
function createDiskCacher(DISK_CACHE_KEY, lifeCycle, storageName = 'localStorage') {
let nowWindow = getWindow();
let storageObject = getter(nowWindow || {}, storageName);
let storage = storageObject ? storageObject
: {
getItem() {},
setItem() {},
removeItem() {},
};
let isMethodExist = storage.getItem instanceof Function;
let result = isMethodExist ? storage.getItem(DISK_CACHE_KEY) : '{}';
let cache = safeJsonParse(result, {}) || {}; //初始化的时候从本地缓存读取数据
let Cacher = CacheFactory(cache, lifeCycle);
return {
Cacher,
getCache(key) {
//读的时候,从内存读取,
return Cacher.getCache(key); //再从内存数据里面获取
},
setCache(key, value) {
//写的时候,才写入本地缓存
Cacher.setCache(key, value); //缓存进行去
let cacheData = Cacher.getData();
try {
storage.setItem(DISK_CACHE_KEY, jsonStringify(cacheData)); //写入本地
} catch (e) {
console.error(
`setCache exception; key=${key}, value=${value}; error=`,
e,
);
this.reportError(key, value);
}
},
getTotalData() {
return Cacher.getData();
},
reportError(key, value) {
key = key + '';
value = value + '';
let totalData = Cacher.getData();
let maxKey = '';
let maxValue = '';
//统计最大和最小的key
Object.keys(totalData).forEach(key => {
let originValue = getter(totalData, `${key}.value`);
let value =
(isObject(originValue)
? jsonStringify(originValue)
: originValue) + '';
if (maxValue.length < value.length) {
maxKey = key;
maxValue = value;
}
});
},
clearCache() {
Cacher.clearCache();
storage.removeItem(DISK_CACHE_KEY);
},
};
}
/**
* @description 内存缓存
* @type {CacheObject}
*/
export const MemoryCache = (function () {
let cache = {};
let lifeCycle = 60 * 1000; //默认缓存1分钟
return CacheFactory(cache, lifeCycle);
})(); // 磁盘缓存
/**
* @description 磁盘缓存,底层是localStorage
* @type {CacheObject | DiskCache}
*/
export const DiskCache = (function () {
const DISK_CACHE_KEY = '_diskCache';
let lifeCycle = 60 * 1000 * 60 * 24 * 365; //默认缓存一年
return createDiskCacher(DISK_CACHE_KEY, lifeCycle, 'localStorage');
})();
/**
* @description 磁盘缓存,底层是sessionStorage
* @type {CacheObject | DiskCache}
*/
export const SessionStorageCache = (function () {
const DISK_CACHE_KEY = '_ssDiskCache';
let lifeCycle = 60 * 1000 * 60 * 24 * 365; //默认缓存一年
return createDiskCacher(DISK_CACHE_KEY, lifeCycle, 'sessionStorage');
})();
Source