/** @type {Function} 日志输出 */ var log = console.warn; /** * 判断值是否为 String 类型 * @param {*} str - 待检测值 * @returns {boolean} * @private */ var isString = function (str) { return Object.getTypeString(str) === 'String'; }; /** * IndexedDB 存储实现(大容量存储优先选择) * * @class IDBStorage * @example * const storage = new IDBStorage('myDb', 'myStore', 1); * await storage.set('key', { data: 123 }); * await storage.get('key', null); */ class IDBStorage { /** * 创建 IndexedDB 存储实例 * @param {string} [dbName='dbName'] - 数据库名称 * @param {string} [storeName='storeName'] - 对象存储名称 * @param {number} [version=1] - 数据库版本号 */ constructor(dbName, storeName, version) { /** @type {number} 数据库版本号 */ this.version = version || 1; /** @type {string} 数据库名称 */ this.dbName = dbName || 'dbName'; /** @type {string} 对象存储名称 */ this.storeName = storeName || 'storeName'; var request = indexedDB.open(this.dbName, this.version); /** @type {Promise} 数据库连接 Promise */ this.requestPromise = new Promise(function (resolve, reject) { request.onupgradeneeded = function (e) { if (e && e.target && !request.result.objectStoreNames.contains(this.storeName)) { request.result.createObjectStore(this.storeName, { keyPath: 'key' }) .createIndex('key', 'key', { unique: false }); } log('[Index][open]-upgrade'); resolve(request.result); }.bind(this); request.onsuccess = function () { log('[IndexDB][open]-success'); resolve(request.result); }; request.onerror = function (e) { log('[IndexDB][open]-error', 2); reject(e); }; }.bind(this)); } /** * 获取存储值 * @template T * @param {string} key - 键名 * @param {T} initValue - 默认值(未找到时返回) * @returns {Promise} 存储的值或默认值 */ get(key, initValue) { var _this = this; return new Promise(async function (resolve) { var db = await _this.requestPromise; var transaction = db.transaction(_this.storeName, 'readonly'); var objectStore = transaction.objectStore(_this.storeName); var req = objectStore.get(key); req.onsuccess = function () { resolve(req.result ? req.result.value : (initValue || null)); }; req.onerror = function (e) { log('[indexDB][get]-error', 2, e); resolve(initValue || null); }; }); } /** * 设置存储值 * @template T * @param {string} key - 键名 * @param {T} value - 要存储的值 * @returns {Promise} 返回写入的值 */ set(key, value) { var _this = this; return new Promise(async function (resolve) { var db = await _this.requestPromise; var transaction = db.transaction(_this.storeName, 'readwrite'); var objectStore = transaction.objectStore(_this.storeName); var req = objectStore.put({ key: key, value: value }); req.onsuccess = function () { resolve(value); }; req.onerror = function (e) { log('[indexDB][set]-error', 2, e); resolve(value); }; }); } } /** * localStorage 存储实现(兼容性好,带内存缓存) * * @class ILocalStorage * @example * const storage = new ILocalStorage(); * await storage.set('key', { data: 456 }); * await storage.get('key', null); */ class ILocalStorage { constructor() { /** @type {Map} 内存缓存 */ this.cache = new Map(); this.load(); } /** 从 localStorage 全量加载到缓存 */ load() { var _this = this; Object.entries(localStorage).forEach(function (entry) { var key = entry[0], value = entry[1]; try { _this.cache.set(key, JSON.parse(value)); } catch (error) { log('[localStorage][load]-error', 2, error, key, value); } }); } /** * 从缓存获取值 * @template T * @param {string} key - 键名 * @param {T} initValue - 默认值 * @returns {Promise} 缓存的值或默认值 */ get(key, initValue) { return new Promise(function (resolve) { resolve(this.cache.get(key) !== undefined ? this.cache.get(key) : initValue); }.bind(this)); } /** * 写入 localStorage 并更新缓存 * @template T * @param {string} key - 键名 * @param {T} value - 要存储的值 * @returns {Promise} 返回写入的值 */ set(key, value) { return new Promise(function (resolve) { var _value = isString(value) ? value : ''; try { _value = JSON.stringify(value); } catch (e) { log('[localStorage][set]-error', 2, e); } localStorage.setItem(key, _value); this.cache.set(key, _value); resolve(value); }.bind(this)); } } // 浏览器环境自动选择存储方式 if (typeof window !== 'undefined') { /** * 当前环境可用的存储类(IDBStorage 或 ILocalStorage) * @type {Function|null} * @global */ window.IStorage = window.indexedDB ? IDBStorage : (window.localStorage ? ILocalStorage : null); if (typeof module !== 'undefined') { module.exports = new window.IStorage(); } } else if (typeof module !== 'undefined') { module.exports = null; }