import localforage from 'localforage'; /** The storage type */ export type StorageType = 'local' | 'session'; // 内存存储的备用实现 class MemoryStorage { private static instance: MemoryStorage; private storage = new Map(); static getInstance() { if (!MemoryStorage.instance) { MemoryStorage.instance = new MemoryStorage(); } return MemoryStorage.instance; } setItem(key: string, value: string) { this.storage.set(key, value); } getItem(key: string) { return this.storage.get(key) || null; } removeItem(key: string) { this.storage.delete(key); } clear() { this.storage.clear(); } } // 全局备用存储实例 const memoryStorage = MemoryStorage.getInstance(); export function createStorage(type: StorageType) { // 尝试获取存储实例,如果失败则使用内存存储 let stg: Storage | MemoryStorage; try { stg = type === 'session' ? window.sessionStorage : window.localStorage; // 测试存储是否可用 stg.setItem('__storage_test__', ''); stg.removeItem('__storage_test__'); } catch (e) { console.warn(`${type} storage is not available, using memory storage`); stg = memoryStorage; } const storage = { set(key: K, value: T[K]) { try { const json = JSON.stringify(value); stg.setItem(key as string, json); } catch (e) { console.warn(`Storage set error, falling back to memory storage`); memoryStorage.setItem(key as string, JSON.stringify(value)); } }, get(key: K): T[K] | null { try { const json = stg.getItem(key as string); if (!json) return null; return JSON.parse(json); } catch (e) { console.warn(`Storage get error, trying memory storage`); try { const memoryValue = memoryStorage.getItem(key as string); return memoryValue ? JSON.parse(memoryValue) : null; } catch { return null; } } }, remove(key: keyof T) { try { stg.removeItem(key as string); memoryStorage.removeItem(key as string); } catch (e) { console.warn(`Storage remove error`); } }, clear() { try { stg.clear(); memoryStorage.clear(); } catch (e) { console.warn(`Storage clear error`); } } }; return storage; } type LocalforageDriver = 'local' | 'indexedDB' | 'webSQL'; export function createLocalforage(driver: LocalforageDriver) { const driverMap: Record = { local: localforage.LOCALSTORAGE, indexedDB: localforage.INDEXEDDB, webSQL: localforage.WEBSQL }; // 创建一个内存存储的备用实现 const memoryStore = new Map(); // 创建备用存储对象 const fallbackStorage = { getItem(key: K): Promise { return Promise.resolve(memoryStore.get(key as string) || null); }, setItem(key: K, value: T[K]): Promise { memoryStore.set(key as string, value); return Promise.resolve(value); }, removeItem(key: keyof T): Promise { memoryStore.delete(key as string); return Promise.resolve(); }, clear(): Promise { memoryStore.clear(); return Promise.resolve(); }, length(): Promise { return Promise.resolve(memoryStore.size); }, key(keyIndex: number): Promise { return Promise.resolve(Array.from(memoryStore.keys())[keyIndex]); }, keys(): Promise { return Promise.resolve(Array.from(memoryStore.keys())); } }; try { // 配置 localforage localforage.config({ driver: [ driverMap[driver], localforage.LOCALSTORAGE, localforage.INDEXEDDB, localforage.WEBSQL ].filter(Boolean), name: 'appStorage', version: 1.0, storeName: 'keyvaluepairs' }); // 创建包装的存储对象 const storage = { getItem(key: K): Promise { return localforage.getItem(key as string) .catch(() => fallbackStorage.getItem(key)); }, setItem(key: K, value: T[K]): Promise { return localforage.setItem(key as string, value) .catch(() => fallbackStorage.setItem(key, value)); }, removeItem(key: keyof T): Promise { return localforage.removeItem(key as string) .catch(() => fallbackStorage.removeItem(key)); }, clear(): Promise { return localforage.clear() .catch(() => fallbackStorage.clear()); }, length(): Promise { return localforage.length() .catch(() => fallbackStorage.length()); }, key(keyIndex: number): Promise { return localforage.key(keyIndex) .catch(() => fallbackStorage.key(keyIndex)); }, keys(): Promise { return localforage.keys() .catch(() => fallbackStorage.keys()); } }; return storage as LocalForage; } catch (e) { console.warn('Localforage initialization failed, using memory storage', e); return fallbackStorage as LocalForage; } } // 更新类型定义 interface LocalForage { getItem(key: K): Promise; setItem(key: K, value: T[K]): Promise; removeItem(key: keyof T): Promise; clear(): Promise; length(): Promise; key(keyIndex: number): Promise; keys(): Promise; }