2026-08-20
JavaScript
0

目录

核心模块
核心接口 IStore.ts
锁机制 StorageLock.ts
存储引擎实现
引擎注册 EngineRegistry.ts
缓存cache
type.ts
LRU
配置管理
命名空间NamespaceManager.ts
工具函数
插件系统
加解密
日志
校验
react/vue 适配
index.ts
example.ts

如何设计一款功能强大的本地存储系统

需求如下:

  1. 使用typescript,提供更好的代码类型提示。
  2. 面向接口编程,IStore接口包括get、set、delete、clear、keys、has、getMany、setMany、sweep、testFunctionality(测试是否支持,存储方案自动降级)、getEngineInfo、close(可选,适配indexdb),支持异步(为了更好的适配indexdb)。
  3. 需要支持多种存储方案,默认实现localStorage、sessionStorage、indexdb、memory这四种,每一种方案都需要实现上面的方法。支持用户自定义存储方案,可以提供一个注册的方法,也可以删除某方案。
  4. 初始化sotre时,指定一个存储方案,也可以通过一个参数开启自动降级(需要有一个参数指定每种方案的优先级,按照这个优先级自动降级)。
  5. 需要加锁。
  6. 用户可以自定义数据加密和解密,以插件的方式,用户需要可以传入。
  7. 日志监控:记录存储操作日志,支持错误上报。也是以插件的方式提供一个默认的,也可以用户自定义。
  8. 数据校验:存储前校验数据格式(基于 Zod/JSON Schema)。
  9. LRU 缓存优化:更高效的内存缓存策略。
  10. 配置化管理:全局统一配置,支持运行时调整。 11.命名空间隔离:多模块存储隔离,避免 key 冲突。
  11. 批量操作优化:IndexedDB 批量操作事务优化。
  12. 响应式 Hook:适配 React/Vue 的响应式存储。
  13. 高级功能要实现用户自主控制,不要在代码写死,暴露一个接口由用户传入实现逻辑

代码调整后目录结构如下:

text
src/ ├── core/ # 核心模块 │ ├── interfaces/ # 接口定义 │ │ └── IStore.ts # 存储核心接口 │ ├── Store.ts # 主存储类 │ ├── engine/ # 存储引擎实现 │ │ ├── index.ts # 引擎导出 │ │ ├── MemoryEngine.ts # 内存存储 │ │ ├── LocalStorageEngine.ts # 本地存储 │ │ ├── SessionStorageEngine.ts # 会话存储 │ │ └── IndexedDBEngine.ts # IndexDB存储 │ ├── lock/ # 锁机制 │ │ └── StorageLock.ts │ └── registry/ # 引擎注册 │ └── EngineRegistry.ts ├── plugins/ # 插件系统 │ ├── crypto/ # 加密插件 │ │ ├── index.ts │ │ ├── types.ts │ │ └── DefaultCrypto.ts │ ├── logger/ # 日志插件 │ │ ├── index.ts │ │ ├── types.ts │ │ └── DefaultLogger.ts │ ├── validator/ # 校验插件 │ │ ├── index.ts │ │ ├── types.ts │ │ └── ZodValidator.ts │ └── reactive/ # 响应式插件 │ ├── index.ts │ ├── types.ts │ ├── ReactHook.ts │ └── VueComposable.ts ├── cache/ # LRU缓存 │ ├── LRUCache.ts │ └── types.ts ├── config/ # 配置管理 │ ├── index.ts │ └── StoreConfig.ts ├── namespace/ # 命名空间 │ └── NamespaceManager.ts ├── utils/ # 工具函数 │ ├── index.ts │ ├── batch.ts # 批量操作优化 │ ├── downgrade.ts # 自动降级 │ └── type-guards.ts └── index.ts # 入口文件

核心模块

核心接口 IStore.ts

ts
/** * 存储引擎信息接口 */ export interface EngineInfo { name: string; version?: string; isSupported: boolean; storageLimit?: number; // 存储限制(MB) persistent: boolean; // 是否持久化 } /** * 核心存储接口 */ export interface IStore { /** * 获取单个值 * @param key 存储键 */ get<T = any>(key: string): Promise<T | null>; /** * 设置单个值 * @param key 存储键 * @param value 存储值 * @param expire? 过期时间(毫秒) */ set<T = any>(key: string, value: T, expire?: number): Promise<boolean>; /** * 删除单个值 * @param key 存储键 */ delete(key: string): Promise<boolean>; /** * 清空所有存储 */ clear(): Promise<boolean>; /** * 获取所有键名 */ keys(): Promise<string[]>; /** * 检查键是否存在 * @param key 存储键 */ has(key: string): Promise<boolean>; /** * 批量获取 * @param keys 键数组 */ getMany<T = any>(keys: string[]): Promise<Record<string, T | null>>; /** * 批量设置 * @param entries 键值对数组 */ setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]>; /** * 清理过期数据 */ sweep(): Promise<number>; // 返回清理的数量 /** * 测试存储方案是否支持 */ testFunctionality(): Promise<boolean>; /** * 获取引擎信息 */ getEngineInfo(): Promise<EngineInfo>; /** * 关闭存储连接(适配IndexedDB) */ close?(): Promise<void>; } /** * 存储引擎构造函数接口 */ export interface IStoreEngineConstructor { new (namespace: string, config?: any): IStore; }

锁机制 StorageLock.ts

ts
/** * 存储锁机制 - 防止并发操作冲突 */ export class StorageLock { private locks = new Map<string, Promise<void>>(); private resolvers = new Map<string, () => void>(); /** * 获取锁 * @param key 锁标识 * @param timeout 超时时间(ms) */ async acquire(key: string, timeout = 5000): Promise<() => void> { // 如果已有锁,等待锁释放 while (this.locks.has(key)) { await Promise.race([ this.locks.get(key), new Promise((_, reject) => setTimeout(() => reject(new Error(`Lock timeout for key: ${key}`)), timeout) ) ]); } // 创建新锁 let resolve: () => void; const lockPromise = new Promise<void>((res) => { resolve = res; }); this.locks.set(key, lockPromise); this.resolvers.set(key, resolve!); // 返回释放锁的函数 return () => this.release(key); } /** * 释放锁 * @param key 锁标识 */ private release(key: string): void { const resolver = this.resolvers.get(key); if (resolver) { resolver(); this.resolvers.delete(key); this.locks.delete(key); } } /** * 带锁执行操作 * @param key 锁标识 * @param fn 要执行的函数 * @param timeout 超时时间 */ async withLock<T>(key: string, fn: () => Promise<T>, timeout = 5000): Promise<T> { const release = await this.acquire(key, timeout); try { return await fn(); } finally { release(); } } /** * 检查锁是否存在 * @param key 锁标识 */ hasLock(key: string): boolean { return this.locks.has(key); } /** * 清空所有锁 */ clear(): void { this.locks.clear(); this.resolvers.clear(); } } // 全局锁实例 export const storageLock = new StorageLock();

存储引擎实现

MemoryEngine.ts
import type{ IStore, EngineInfo } from "../interfaces/IStore"; import { LRUCache } from "../../cache/LRUCache"; /** * 内存存储引擎 */ export class MemoryEngine implements IStore { private storage = new LRUCache(); private namespace: string; constructor(namespace: string, config?: { cacheSize?: number }) { this.namespace = namespace; if (config?.cacheSize) { this.storage.setMaxSize(config.cacheSize); } } /** * 获取单个值 */ async get<T = any>(key: string): Promise<T | null> { return this.storage.get(key) as T | null; } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number): Promise<boolean> { try { this.storage.set(key, value, expire || null); return true; } catch (error) { return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { if (!this.storage.has(key)) { return false; } this.storage.delete(key); return true; } /** * 清空所有存储 */ async clear(): Promise<boolean> { try { this.storage.clear(); return true; } catch (error) { return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { return this.storage.keys(); } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { return this.storage.has(key); } /** * 批量获取 */ async getMany<T = any>(keys: string[]): Promise<Record<string, T | null>> { const result: Record<string, T | null> = {}; for (const key of keys) { result[key] = this.storage.get(key) as T | null; } return result; } /** * 批量设置 */ async setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]> { const results: boolean[] = []; for (const entry of entries) { try { this.storage.set(entry.key, entry.value, entry.expire || null); results.push(true); } catch (error) { results.push(false); } } return results; } /** * 清理过期数据 */ async sweep(): Promise<number> { return this.storage.sweep(); } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { // 内存存储始终支持 return true; } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { return { name: 'memory', version: '1.0.0', isSupported: true, storageLimit: Number.MAX_SAFE_INTEGER, // 理论上无限制 persistent: false // 页面刷新后丢失 }; } }
LocalStorageEngine.ts
import type{ IStore, EngineInfo } from "../interfaces/IStore"; import { namespaceManager } from "../../namespace/NamespaceManager"; /** * 存储值结构 */ interface StoredValue { data: any; expire: number | null; } /** * localStorage存储引擎 */ export class LocalStorageEngine implements IStore { private namespace: string; constructor(namespace: string) { this.namespace = namespace; } /** * 获取命名空间后的键 */ private getNamespacedKey(key: string): string { return namespaceManager.getNamespacedKey(this.namespace, key); } /** * 获取单个值 */ async get<T = any>(key: string): Promise<T | null> { try { const namespacedKey = this.getNamespacedKey(key); const item = localStorage.getItem(namespacedKey); if (!item) return null; const parsed: StoredValue = JSON.parse(item); // 检查过期时间 if (parsed.expire && Date.now() > parsed.expire) { localStorage.removeItem(namespacedKey); return null; } return parsed.data as T; } catch (error) { return null; } } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); const storedValue: StoredValue = { data: value, expire: expire ? Date.now() + expire : null }; localStorage.setItem(namespacedKey, JSON.stringify(storedValue)); return true; } catch (error) { return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); if (!localStorage.getItem(namespacedKey)) { return false; } localStorage.removeItem(namespacedKey); return true; } catch (error) { return false; } } /** * 清空所有存储 */ async clear(): Promise<boolean> { try { // 只清空当前命名空间的键 const keys = await this.keys(); for (const key of keys) { localStorage.removeItem(this.getNamespacedKey(key)); } return true; } catch (error) { return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { try { const keys: string[] = []; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); if (key && namespaceManager.isInNamespace(key, this.namespace)) { keys.push(namespaceManager.extractOriginalKey(key, this.namespace)); } } return keys; } catch (error) { return []; } } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return !!localStorage.getItem(namespacedKey); } catch (error) { return false; } } /** * 批量获取 */ async getMany<T = any>(keys: string[]): Promise<Record<string, T | null>> { const result: Record<string, T | null> = {}; for (const key of keys) { result[key] = await this.get<T>(key); } return result; } /** * 批量设置 */ async setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]> { const results: boolean[] = []; for (const entry of entries) { results.push(await this.set(entry.key, entry.value, entry.expire)); } return results; } /** * 清理过期数据 */ async sweep(): Promise<number> { try { const keys = await this.keys(); let count = 0; for (const key of keys) { const namespacedKey = this.getNamespacedKey(key); const item = localStorage.getItem(namespacedKey); if (item) { const parsed: StoredValue = JSON.parse(item); if (parsed.expire && Date.now() > parsed.expire) { localStorage.removeItem(namespacedKey); count++; } } } return count; } catch (error) { return 0; } } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { try { const testKey = this.getNamespacedKey('__test__'); localStorage.setItem(testKey, 'test'); localStorage.removeItem(testKey); return true; } catch (error) { return false; } } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { return { name: 'localStorage', version: '1.0.0', isSupported: await this.testFunctionality(), storageLimit: 5, // 通常5MB persistent: true }; } }
SessionStorageEngine.ts
import type{ IStore, EngineInfo } from "../interfaces/IStore"; import { namespaceManager } from "../../namespace/NamespaceManager"; /** * 存储值结构 */ interface StoredValue { data: any; expire: number | null; } /** * sessionStorage存储引擎 */ export class SessionStorageEngine implements IStore { private namespace: string; constructor(namespace: string) { this.namespace = namespace; } /** * 获取命名空间后的键 */ private getNamespacedKey(key: string): string { return namespaceManager.getNamespacedKey(this.namespace, key); } /** * 获取单个值 */ async get<T = any>(key: string): Promise<T | null> { try { const namespacedKey = this.getNamespacedKey(key); const item = sessionStorage.getItem(namespacedKey); if (!item) return null; const parsed: StoredValue = JSON.parse(item); // 检查过期时间 if (parsed.expire && Date.now() > parsed.expire) { sessionStorage.removeItem(namespacedKey); return null; } return parsed.data as T; } catch (error) { return null; } } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); const storedValue: StoredValue = { data: value, expire: expire ? Date.now() + expire : null }; sessionStorage.setItem(namespacedKey, JSON.stringify(storedValue)); return true; } catch (error) { return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); if (!sessionStorage.getItem(namespacedKey)) { return false; } sessionStorage.removeItem(namespacedKey); return true; } catch (error) { return false; } } /** * 清空所有存储 */ async clear(): Promise<boolean> { try { // 只清空当前命名空间的键 const keys = await this.keys(); for (const key of keys) { sessionStorage.removeItem(this.getNamespacedKey(key)); } return true; } catch (error) { return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { try { const keys: string[] = []; for (let i = 0; i < sessionStorage.length; i++) { const key = sessionStorage.key(i); if (key && namespaceManager.isInNamespace(key, this.namespace)) { keys.push(namespaceManager.extractOriginalKey(key, this.namespace)); } } return keys; } catch (error) { return []; } } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return !!sessionStorage.getItem(namespacedKey); } catch (error) { return false; } } /** * 批量获取 */ async getMany<T = any>(keys: string[]): Promise<Record<string, T | null>> { const result: Record<string, T | null> = {}; for (const key of keys) { result[key] = await this.get<T>(key); } return result; } /** * 批量设置 */ async setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]> { const results: boolean[] = []; for (const entry of entries) { results.push(await this.set(entry.key, entry.value, entry.expire)); } return results; } /** * 清理过期数据 */ async sweep(): Promise<number> { try { const keys = await this.keys(); let count = 0; for (const key of keys) { const namespacedKey = this.getNamespacedKey(key); const item = sessionStorage.getItem(namespacedKey); if (item) { const parsed: StoredValue = JSON.parse(item); if (parsed.expire && Date.now() > parsed.expire) { sessionStorage.removeItem(namespacedKey); count++; } } } return count; } catch (error) { return 0; } } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { try { const testKey = this.getNamespacedKey('__test__'); sessionStorage.setItem(testKey, 'test'); sessionStorage.removeItem(testKey); return true; } catch (error) { return false; } } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { return { name: 'sessionStorage', version: '1.0.0', isSupported: await this.testFunctionality(), storageLimit: 5, // 通常5MB persistent: false // 会话结束后丢失 }; } }
IndexedDBEngine.ts
import type{ IStore, EngineInfo } from "../interfaces/IStore"; import { namespaceManager } from "../../namespace/NamespaceManager"; import { batchOptimize } from "../../utils/batch"; /** * IndexedDB存储值接口 */ interface DBValue { id: string; // 带命名空间的key data: any; expire: number | null; createdAt: number; updatedAt: number; } /** * IndexedDB存储引擎 */ export class IndexedDBEngine implements IStore { private dbName: string; private storeName: string; private version: number; private namespace: string; private db: IDBDatabase | null = null; constructor(namespace: string, config?: { dbName?: string; storeName?: string; version?: number }) { this.namespace = namespace; this.dbName = config?.dbName || 'enterprise-store'; this.storeName = config?.storeName || 'data'; this.version = config?.version || 1; } /** * 打开数据库连接 */ private async openDB(): Promise<IDBDatabase> { if (this.db) { return this.db; } return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, this.version); // 数据库升级 request.onupgradeneeded = (event) => { const db = (event.target as IDBOpenDBRequest).result; // 创建对象存储 if (!db.objectStoreNames.contains(this.storeName)) { const store = db.createObjectStore(this.storeName, { keyPath: 'id' }); // 创建索引 store.createIndex('expire', 'expire', { unique: false }); store.createIndex('namespace', 'namespace', { unique: false }); } }; request.onsuccess = (event) => { this.db = (event.target as IDBOpenDBRequest).result; resolve(this.db); }; request.onerror = (event) => { reject(new Error(`Failed to open IndexedDB: ${(event.target as IDBOpenDBRequest).error?.message}`)); }; request.onblocked = () => { reject(new Error('IndexedDB upgrade blocked')); }; }); } /** * 获取命名空间后的键 */ private getNamespacedKey(key: string): string { return namespaceManager.getNamespacedKey(this.namespace, key); } /** * 执行数据库操作 */ private async execute<T>( mode: IDBTransactionMode, operation: (store: IDBObjectStore) => Promise<T> ): Promise<T> { const db = await this.openDB(); return new Promise((resolve, reject) => { const transaction = db.transaction(this.storeName, mode); const store = transaction.objectStore(this.storeName); operation(store) .then(resolve) .catch(reject); transaction.oncomplete = () => {}; transaction.onerror = (event) => { reject(new Error(`Transaction error: ${(event.target as IDBTransaction).error?.message}`)); }; transaction.onabort = (event) => { reject(new Error(`Transaction aborted: ${(event.target as IDBTransaction).error?.message}`)); }; }); } /** * 获取单个值 */ async get<T = any>(key: string): Promise<T | null> { try { const namespacedKey = this.getNamespacedKey(key); return this.execute('readonly', async (store) => { return new Promise((resolve, reject) => { const request = store.get(namespacedKey); request.onsuccess = (event) => { const result = (event.target as IDBRequest).result as DBValue | undefined; if (!result) { resolve(null); return; } // 检查过期时间 if (result.expire && Date.now() > result.expire) { // 删除过期数据 store.delete(namespacedKey); resolve(null); return; } resolve(result.data as T); }; request.onerror = (event) => { reject(new Error(`Get error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return null; } } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return this.execute('readwrite', async (store) => { return new Promise((resolve, reject) => { const dbValue: DBValue = { id: namespacedKey, data: value, expire: expire ? Date.now() + expire : null, createdAt: Date.now(), updatedAt: Date.now() }; const request = store.put(dbValue); request.onsuccess = () => { resolve(true); }; request.onerror = (event) => { reject(new Error(`Set error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return this.execute('readwrite', async (store) => { return new Promise((resolve, reject) => { // 先检查是否存在 const getRequest = store.get(namespacedKey); getRequest.onsuccess = (event) => { const exists = !!((event.target as IDBRequest).result); if (!exists) { resolve(false); return; } // 执行删除 const deleteRequest = store.delete(namespacedKey); deleteRequest.onsuccess = () => { resolve(true); }; deleteRequest.onerror = (event) => { reject(new Error(`Delete error: ${(event.target as IDBRequest).error?.message}`)); }; }; getRequest.onerror = (event) => { reject(new Error(`Delete check error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return false; } } /** * 清空所有存储 */ async clear(): Promise<boolean> { try { return this.execute('readwrite', async (store) => { return new Promise((resolve, reject) => { // 获取当前命名空间的所有键 const keys: string[] = []; const cursorRequest = store.openCursor(); cursorRequest.onsuccess = (event) => { const cursor = (event.target as IDBRequest).result as IDBCursorWithValue; if (cursor) { const dbValue = cursor.value as DBValue; if (namespaceManager.isInNamespace(dbValue.id, this.namespace)) { keys.push(dbValue.id); cursor.delete(); // 直接删除 } cursor.continue(); } else { // 游标遍历完成 resolve(true); } }; cursorRequest.onerror = (event) => { reject(new Error(`Clear error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { try { return this.execute('readonly', async (store) => { return new Promise((resolve, reject) => { const keys: string[] = []; const cursorRequest = store.openCursor(); cursorRequest.onsuccess = (event) => { const cursor = (event.target as IDBRequest).result as IDBCursorWithValue; if (cursor) { const dbValue = cursor.value as DBValue; if (namespaceManager.isInNamespace(dbValue.id, this.namespace)) { keys.push(namespaceManager.extractOriginalKey(dbValue.id, this.namespace)); } cursor.continue(); } else { resolve(keys); } }; cursorRequest.onerror = (event) => { reject(new Error(`Keys error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return []; } } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return this.execute('readonly', async (store) => { return new Promise((resolve, reject) => { const request = store.get(namespacedKey); request.onsuccess = (event) => { resolve(!!((event.target as IDBRequest).result)); }; request.onerror = (event) => { reject(new Error(`Has error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return false; } } /** * 批量获取 - 优化版 */ async getMany<T = any>(keys: string[]): Promise<Record<string, T | null>> { try { // 使用批量操作优化 return batchOptimize<Record<string, T | null>>( () => this.execute('readonly', async (store) => { const result: Record<string, T | null> = {}; const namespacedKeys = keys.map(key => this.getNamespacedKey(key)); // 并行获取所有值 await Promise.all(namespacedKeys.map(async (namespacedKey, index) => { const originalKey = keys[index]; try { const value = await new Promise<DBValue | undefined>((resolve) => { const request = store.get(namespacedKey); request.onsuccess = (event) => { resolve((event.target as IDBRequest).result as DBValue | undefined); }; request.onerror = () => resolve(undefined); }); if (!value) { result[originalKey] = null; return; } // 检查过期 if (value.expire && Date.now() > value.expire) { result[originalKey] = null; // 异步删除过期数据(不阻塞当前操作) store.delete(namespacedKey); return; } result[originalKey] = value.data as T; } catch (error) { result[originalKey] = null; } })); return result; }) ); } catch (error) { return keys.reduce((acc, key) => ({ ...acc, [key]: null }), {}); } } /** * 批量设置 - 优化版 */ async setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]> { try { // 使用批量操作优化 return batchOptimize<boolean[]>( () => this.execute('readwrite', async (store) => { const results: boolean[] = []; // 批量插入所有值 await Promise.all(entries.map(async (entry) => { try { const namespacedKey = this.getNamespacedKey(entry.key); const dbValue: DBValue = { id: namespacedKey, data: entry.value, expire: entry.expire ? Date.now() + entry.expire : null, createdAt: Date.now(), updatedAt: Date.now() }; await new Promise<void>((resolve) => { const request = store.put(dbValue); request.onsuccess = () => resolve(); request.onerror = () => resolve(); }); results.push(true); } catch (error) { results.push(false); } })); return results; }) ); } catch (error) { return entries.map(() => false); } } /** * 清理过期数据 */ async sweep(): Promise<number> { try { return this.execute('readwrite', async (store) => { return new Promise((resolve, reject) => { let count = 0; const now = Date.now(); // 使用索引查询过期数据 const index = store.index('expire'); const cursorRequest = index.openCursor(IDBKeyRange.upperBound(now)); cursorRequest.onsuccess = (event) => { const cursor = (event.target as IDBRequest).result as IDBCursorWithValue; if (cursor) { const dbValue = cursor.value as DBValue; // 只清理当前命名空间的过期数据 if (namespaceManager.isInNamespace(dbValue.id, this.namespace)) { cursor.delete(); count++; } cursor.continue(); } else { resolve(count); } }; cursorRequest.onerror = (event) => { reject(new Error(`Sweep error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return 0; } } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { if (!('indexedDB' in window)) { return false; } try { const testDbName = `${this.dbName}-test`; const testStoreName = 'test'; return new Promise((resolve) => { const request = indexedDB.open(testDbName, 1); request.onupgradeneeded = (event) => { const db = (event.target as IDBOpenDBRequest).result; if (!db.objectStoreNames.contains(testStoreName)) { db.createObjectStore(testStoreName); } }; request.onsuccess = (event) => { const db = (event.target as IDBOpenDBRequest).result; // 清理测试数据库 indexedDB.deleteDatabase(testDbName); db.close(); resolve(true); }; request.onerror = () => { resolve(false); }; request.onblocked = () => { resolve(false); }; }); } catch (error) { return false; } } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { const isSupported = await this.testFunctionality(); return { name: 'indexeddb', version: '1.0.0', isSupported, storageLimit: isSupported ? 50 : 0, // 通常50MB+ persistent: true }; } /** * 关闭数据库连接 */ async close(): Promise<void> { if (this.db) { this.db.close(); this.db = null; } } }

引擎注册 EngineRegistry.ts

ts
import type { IStoreEngineConstructor } from "../interfaces/IStore"; /** * 存储引擎注册器 - 管理所有可用的存储引擎 */ export class EngineRegistry { private static instance: EngineRegistry; private engines = new Map<string, IStoreEngineConstructor>(); private constructor() {} /** * 获取单例实例 */ public static getInstance(): EngineRegistry { if (!EngineRegistry.instance) { EngineRegistry.instance = new EngineRegistry(); } return EngineRegistry.instance; } /** * 注册存储引擎 * @param name 引擎名称 * @param constructor 引擎构造函数 */ public registerEngine(name: string, constructor: IStoreEngineConstructor): void { if (this.engines.has(name)) { console.warn(`Engine "${name}" is already registered, it will be overwritten`); } this.engines.set(name, constructor); } /** * 注销存储引擎 * @param name 引擎名称 */ public unregisterEngine(name: string): boolean { return this.engines.delete(name); } /** * 获取存储引擎构造函数 * @param name 引擎名称 */ public getEngine(name: string): IStoreEngineConstructor | undefined { return this.engines.get(name); } /** * 获取所有已注册的引擎名称 */ public getRegisteredEngines(): string[] { return Array.from(this.engines.keys()); } /** * 检查引擎是否已注册 * @param name 引擎名称 */ public hasEngine(name: string): boolean { return this.engines.has(name); } /** * 清空所有引擎 */ public clear(): void { this.engines.clear(); } } // 全局注册器实例 export const engineRegistry = EngineRegistry.getInstance();

主存储模块

import type{ IStore, EngineInfo, IStoreEngineConstructor } from "./interfaces/IStore"; import { engineRegistry } from "./registry/EngineRegistry"; import { configManager } from "../config/StoreConfig"; import type{ StoreConfig, RuntimeConfig } from "../config/StoreConfig"; import { storageLock } from "./lock/StorageLock"; import { namespaceManager } from "../namespace/NamespaceManager"; import { LRUCache } from "../cache/LRUCache"; import type{ CryptoPlugin } from "../plugins/crypto"; import { DefaultCrypto } from "../plugins/crypto/DefaultCrypto"; import type{ LoggerPlugin, LogEntry } from "../plugins/logger"; import { DefaultLogger } from "../plugins/logger/DefaultLogger"; import type{ ValidatorPlugin } from "../plugins/validator"; import { ZodValidator } from "../plugins/validator/ZodValidator"; import { checkEngineSupport, getFallbackEngine } from "../utils/downgrade"; import { assertExists } from "../utils/type-guards"; /** * 企业级存储主类 */ export class EnterpriseStore implements IStore { private engine: IStore; private namespace: string; private config: StoreConfig; private lruCache?: LRUCache; private cryptoPlugin: CryptoPlugin; private loggerPlugin: LoggerPlugin; private validatorPlugin?: ValidatorPlugin; private encryptionKey?: string; /** * 私有构造函数(禁止直接实例化,使用 create 静态方法) */ private constructor(options: { engine: IStore; namespace: string; config: StoreConfig; cryptoPlugin: CryptoPlugin; loggerPlugin: LoggerPlugin; validatorPlugin?: ValidatorPlugin; encryptionKey?: string; }) { this.engine = options.engine; this.namespace = options.namespace; this.config = options.config; this.cryptoPlugin = options.cryptoPlugin; this.loggerPlugin = options.loggerPlugin; this.validatorPlugin = options.validatorPlugin; this.encryptionKey = options.encryptionKey; // 初始化LRU缓存 if (this.config.enableLRUCache) { this.lruCache = new LRUCache(this.config.lruCacheSize); } } /** * 静态创建方法(处理异步初始化) * @param options 配置选项 */ public static async create(options?: { namespace?: string; engine?: string; config?: RuntimeConfig; cryptoPlugin?: CryptoPlugin; loggerPlugin?: LoggerPlugin; validatorPlugin?: ValidatorPlugin; encryptionKey?: string; }): Promise<EnterpriseStore> { // 初始化配置 const globalConfig = configManager.getConfig(); const config: StoreConfig = { ...globalConfig, cryptoPlugin: options?.cryptoPlugin || new DefaultCrypto(), loggerPlugin: options?.loggerPlugin || new DefaultLogger(), validatorPlugin: options?.validatorPlugin || new ZodValidator() }; // 更新运行时配置 if (options?.config) { configManager.updateConfig(options.config); } // 设置命名空间 const namespace = options?.namespace || config.defaultNamespace; // 设置加密插件和密钥 const cryptoPlugin = config.cryptoPlugin!; const encryptionKey = options?.encryptionKey; // 设置日志插件 const loggerPlugin = config.loggerPlugin!; // 设置校验插件 const validatorPlugin = config.enableValidation ? config.validatorPlugin : undefined; // 初始化存储引擎(异步) const engineName = options?.engine || config.defaultEngine; const engine = await EnterpriseStore.initEngine(engineName, namespace, config, loggerPlugin); return new EnterpriseStore({ engine, namespace, config, cryptoPlugin, loggerPlugin, validatorPlugin, encryptionKey }); } /** * 异步初始化存储引擎(支持自动降级) */ private static async initEngine( engineName: string, namespace: string, config: StoreConfig, logger: LoggerPlugin ): Promise<IStore> { // 尝试创建指定引擎 try { const EngineConstructor = engineRegistry.getEngine(engineName); if (!EngineConstructor) { throw new Error(`Engine "${engineName}" is not registered`); } const engine = new EngineConstructor(namespace, config); // 异步测试引擎是否支持 const isSupported = await engine.testFunctionality(); if (!isSupported) { throw new Error(`Engine "${engineName}" is not supported in this environment`); } return engine; } catch (error) { logger.reportError( error as Error, { namespace, engine: engineName, action: 'initEngine' } ); // 自动降级(异步获取降级引擎) if (config.enableAutoDowngrade) { const fallbackEngineName = await getFallbackEngine(engineName); // 关键修复:添加 await if (fallbackEngineName) { await logger.log({ timestamp: Date.now(), level: 'warn', operation: 'test', namespace, engine: engineName, success: false, metadata: { fallbackTo: fallbackEngineName } } as LogEntry); // 递归初始化降级引擎(异步) return this.initEngine(fallbackEngineName, namespace, config, logger); } } throw new Error(`Failed to initialize any storage engine: ${(error as Error).message}`); } } /** * 记录操作日志 */ private async logOperation( operation: LogEntry['operation'], key: string | string[] | undefined, success: boolean, startTime: number, error?: Error, metadata?: Record<string, any> ): Promise<void> { if (!this.config.enableLogger) return; const engineInfo = await this.engine.getEngineInfo(); await this.loggerPlugin.log({ timestamp: Date.now(), level: success ? 'info' : 'error', operation, key, namespace: this.namespace, engine: engineInfo.name, duration: Date.now() - startTime, success, error, metadata } as LogEntry); } /** * 加密数据 */ private async encryptData<T = any>(data: T): Promise<string> { if (!this.config.enableCrypto) { return JSON.stringify(data); } const encrypted = await this.cryptoPlugin.encrypt(data, this.encryptionKey); return typeof encrypted === 'string' ? encrypted : JSON.stringify(encrypted); } /** * 解密数据 */ private async decryptData<T = any>(encryptedData: string): Promise<T> { if (!this.config.enableCrypto) { try { return JSON.parse(encryptedData) as T; } catch (e) { return encryptedData as unknown as T; } } return this.cryptoPlugin.decrypt<T>(encryptedData, this.encryptionKey); } /** * 校验数据 */ private async validateData<T = any>(data: T, schema?: any): Promise<boolean> { if (!this.config.enableValidation || !this.validatorPlugin || !schema) { return true; } const result = await this.validatorPlugin.validate(data, schema); if (!result.valid && result.errors) { throw new Error(`Data validation failed: ${result.errors.join(', ')}`); } return result.valid; } /** * 获取单个值 */ async get<T = any>(key: string, schema?: any): Promise<T | null> { const startTime = Date.now(); const lockKey = `${this.namespace}:${key}`; try { return await storageLock.withLock(lockKey, async () => { // 先从LRU缓存获取 if (this.lruCache?.has(key)) { const cached = this.lruCache.get(key); await this.logOperation('get', key, true, startTime, undefined, { fromCache: true }); return cached as T | null; } // 从存储引擎获取 const encryptedData = await this.engine.get<string>(key); if (encryptedData === null) { await this.logOperation('get', key, true, startTime); return null; } // 确保是字符串类型 const encryptedStr = typeof encryptedData === 'string' ? encryptedData : JSON.stringify(encryptedData); // 解密数据 const data = await this.decryptData<T>(encryptedStr); // 校验数据 if (schema) { await this.validateData(data, schema); } // 更新LRU缓存 this.lruCache?.set(key, data); await this.logOperation('get', key, true, startTime); return data; }); } catch (error) { await this.logOperation('get', key, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'get' }); return null; } } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number, schema?: any): Promise<boolean> { const startTime = Date.now(); const lockKey = `${this.namespace}:${key}`; try { return await storageLock.withLock(lockKey, async () => { // 校验数据 if (schema) { await this.validateData(value, schema); } // 加密数据 const encryptedData = await this.encryptData(value); // 存储到引擎 const result = await this.engine.set<string>( key, encryptedData, expire || this.config.defaultExpire ); // 更新LRU缓存 if (result && this.lruCache) { this.lruCache.set(key, value, expire || this.config.defaultExpire); } await this.logOperation('set', key, result, startTime); return result; }); } catch (error) { await this.logOperation('set', key, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'set' }); return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { const startTime = Date.now(); const lockKey = `${this.namespace}:${key}`; try { return await storageLock.withLock(lockKey, async () => { const result = await this.engine.delete(key); if (result && this.lruCache) { this.lruCache.delete(key); } await this.logOperation('delete', key, result, startTime); return result; }); } catch (error) { await this.logOperation('delete', key, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'delete' }); return false; } } /** * 清空所有存储 */ async clear(): Promise<boolean> { const startTime = Date.now(); const lockKey = `${this.namespace}:clear`; try { return await storageLock.withLock(lockKey, async () => { const result = await this.engine.clear(); if (result && this.lruCache) { this.lruCache.clear(); } await this.logOperation('clear', undefined, result, startTime); return result; }); } catch (error) { await this.logOperation('clear', undefined, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'clear' }); return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { const startTime = Date.now(); try { const keys = await this.engine.keys(); await this.logOperation('keys', undefined, true, startTime); return keys; } catch (error) { await this.logOperation('keys', undefined, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'keys' }); return []; } } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { const startTime = Date.now(); try { if (this.lruCache?.has(key)) { await this.logOperation('has', key, true, startTime, undefined, { fromCache: true }); return true; } const result = await this.engine.has(key); await this.logOperation('has', key, true, startTime); return result; } catch (error) { await this.logOperation('has', key, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'has' }); return false; } } /** * 批量获取 */ async getMany<T = any>(keys: string[], schemas?: Record<string, any>): Promise<Record<string, T | null>> { const startTime = Date.now(); const lockKey = `${this.namespace}:batch:get`; try { return await storageLock.withLock(lockKey, async () => { const encryptedResults = await this.engine.getMany<string>(keys); const results: Record<string, T | null> = {}; for (const key of keys) { if (encryptedResults[key] === null) { results[key] = null; continue; } try { const encryptedStr = typeof encryptedResults[key] === 'string' ? encryptedResults[key]! : JSON.stringify(encryptedResults[key]); const data = await this.decryptData<T>(encryptedStr); if (schemas?.[key]) { await this.validateData(data, schemas[key]); } this.lruCache?.set(key, data); results[key] = data; } catch (error) { results[key] = null; this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'getMany' }); } } await this.logOperation('batch', keys, true, startTime); return results; }); } catch (error) { await this.logOperation('batch', keys, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'getMany' }); return keys.reduce((acc, key) => ({ ...acc, [key]: null }), {}); } } /** * 批量设置 */ async setMany<T = any>( entries: Array<{ key: string; value: T; expire?: number; schema?: any }> ): Promise<boolean[]> { const startTime = Date.now(); const lockKey = `${this.namespace}:batch:set`; try { return await storageLock.withLock(lockKey, async () => { const encryptedEntries = []; for (const entry of entries) { if (entry.schema) { await this.validateData(entry.value, entry.schema); } const encryptedData = await this.encryptData(entry.value); encryptedEntries.push({ key: entry.key, value: encryptedData, expire: entry.expire || this.config.defaultExpire }); } const results = await this.engine.setMany<string>(encryptedEntries); for (let i = 0; i < entries.length; i++) { if (results[i] && this.lruCache) { this.lruCache.set( entries[i].key, entries[i].value, entries[i].expire || this.config.defaultExpire ); } } await this.logOperation('batch', entries.map(e => e.key), true, startTime); return results; }); } catch (error) { await this.logOperation('batch', entries.map(e => e.key), false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'setMany' }); return entries.map(() => false); } } /** * 清理过期数据 */ async sweep(): Promise<number> { const startTime = Date.now(); const lockKey = `${this.namespace}:sweep`; try { const count = await storageLock.withLock(lockKey, async () => { const engineCount = await this.engine.sweep(); const cacheCount = this.lruCache?.sweep() || 0; return engineCount + cacheCount; }); await this.logOperation('sweep', undefined, true, startTime, undefined, { count }); return count; } catch (error) { await this.logOperation('sweep', undefined, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'sweep' }); return 0; } } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { const startTime = Date.now(); try { const result = await this.engine.testFunctionality(); await this.logOperation('test', undefined, result, startTime); return result; } catch (error) { await this.logOperation('test', undefined, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'testFunctionality' }); return false; } } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { return this.engine.getEngineInfo(); } /** * 关闭存储连接 */ async close(): Promise<void> { if (typeof this.engine.close === 'function') { await this.engine.close(); } this.lruCache?.clear(); storageLock.clear(); } /** * 更新配置 */ updateConfig(newConfig: RuntimeConfig): void { configManager.updateConfig(newConfig); if (newConfig.enableLRUCache !== undefined && !newConfig.enableLRUCache) { this.lruCache?.clear(); } else if (newConfig.lruCacheSize && this.lruCache) { this.lruCache.setMaxSize(newConfig.lruCacheSize); } } /** * 切换存储引擎(异步) */ async switchEngine(engineName: string): Promise<boolean> { try { const newEngine = await EnterpriseStore.initEngine( engineName, this.namespace, this.config, this.loggerPlugin ); this.engine = newEngine; this.lruCache?.clear(); return true; } catch (error) { this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'switchEngine', engineName }); return false; } } /** * 获取当前命名空间 */ getNamespace(): string { return this.namespace; } /** * 切换命名空间 */ switchNamespace(namespace: string): void { this.namespace = namespace; this.lruCache?.clear(); } }

缓存cache

type.ts

ts
/** * 缓存项接口 */ export interface CacheEntry<T = any> { /** * 缓存值 */ value: T; /** * 过期时间戳(ms) */ expire: number | null; /** * 最后访问时间戳 */ lastAccessed: number; /** * 访问次数 */ accessCount?: number; } /** * 缓存策略类型 */ export type CachePolicy = 'LRU' | 'LFU' | 'FIFO'; /** * 缓存配置接口 */ export interface CacheConfig { /** * 最大缓存大小 */ maxSize: number; /** * 缓存策略 */ policy: CachePolicy; /** * 默认过期时间(ms) */ defaultExpire: number | null; /** * 是否自动清理过期项 */ autoSweep: boolean; /** * 自动清理间隔(ms) */ sweepInterval: number; }

LRU

ts
interface CacheEntry<T = any> { value: T; expire: number | null; lastAccessed: number; } /** * LRU缓存实现 - 优化内存使用 */ export class LRUCache<T = any> { private cache = new Map<string, CacheEntry<T>>(); private maxSize: number; constructor(maxSize = 100) { this.maxSize = maxSize; } /** * 获取缓存值 * @param key 缓存键 */ get(key: string): T | null { const entry = this.cache.get(key); if (!entry) return null; // 检查是否过期 if (entry.expire && Date.now() > entry.expire) { this.cache.delete(key); return null; } // 更新最后访问时间 entry.lastAccessed = Date.now(); this.cache.set(key, entry); return entry.value; } /** * 设置缓存值 * @param key 缓存键 * @param value 缓存值 * @param expire 过期时间(ms) */ set(key: string, value: T, expire: number | null = null): void { // 如果达到最大容量,移除最久未使用的项 if (this.cache.size >= this.maxSize) { const oldestKey = Array.from(this.cache.entries()) .sort((a, b) => a[1].lastAccessed - b[1].lastAccessed)[0][0]; this.cache.delete(oldestKey); } this.cache.set(key, { value, expire: expire ? Date.now() + expire : null, lastAccessed: Date.now() }); } /** * 删除缓存项 * @param key 缓存键 */ delete(key: string): void { this.cache.delete(key); } /** * 检查缓存项是否存在 * @param key 缓存键 */ has(key: string): boolean { const entry = this.cache.get(key); if (!entry) return false; // 检查是否过期 if (entry.expire && Date.now() > entry.expire) { this.cache.delete(key); return false; } return true; } /** * 获取所有缓存键 */ keys(): string[] { // 清理过期项 this.sweep(); return Array.from(this.cache.keys()); } /** * 清理过期项 */ sweep(): number { const now = Date.now(); let count = 0; for (const [key, entry] of this.cache.entries()) { if (entry.expire && now > entry.expire) { this.cache.delete(key); count++; } } return count; } /** * 清空缓存 */ clear(): void { this.cache.clear(); } /** * 获取缓存大小 */ get size(): number { return this.cache.size; } /** * 设置最大缓存大小 * @param size 最大容量 */ setMaxSize(size: number): void { this.maxSize = size; // 如果当前大小超过新限制,移除多余项 while (this.cache.size > this.maxSize) { const oldestKey = Array.from(this.cache.entries()) .sort((a, b) => a[1].lastAccessed - b[1].lastAccessed)[0][0]; this.cache.delete(oldestKey); } } }

配置管理

ts
import type{ CryptoPlugin } from "../plugins/crypto"; import type{ LoggerPlugin } from "../plugins/logger"; import type{ ValidatorPlugin } from "../plugins/validator"; /** * 引擎优先级配置 */ export type EnginePriority = string[]; /** * 全局存储配置 */ export interface StoreGlobalConfig { // 默认存储引擎 defaultEngine: string; // 引擎优先级(用于自动降级) enginePriority: EnginePriority; // 是否开启自动降级 enableAutoDowngrade: boolean; // 默认命名空间 defaultNamespace: string; // 是否开启LRU缓存 enableLRUCache: boolean; // LRU缓存大小 lruCacheSize: number; // 是否开启锁机制 enableLock: boolean; // 锁超时时间(ms) lockTimeout: number; // 是否开启日志 enableLogger: boolean; // 是否开启加密 enableCrypto: boolean; // 是否开启数据校验 enableValidation: boolean; // 默认过期时间(ms) defaultExpire: number | null; // IndexedDB配置 indexeddb?: { dbName: string; storeName: string; version: number; }; } /** * 运行时可配置的选项 */ export type RuntimeConfig = Partial<Omit<StoreGlobalConfig, 'indexeddb'>>; /** * 完整配置(包含插件) */ export interface StoreConfig extends StoreGlobalConfig { // 加密插件 cryptoPlugin?: CryptoPlugin; // 日志插件 loggerPlugin?: LoggerPlugin; // 校验插件 validatorPlugin?: ValidatorPlugin; } /** * 默认全局配置 */ export const defaultConfig: StoreGlobalConfig = { defaultEngine: 'localStorage', enginePriority: ['indexeddb', 'localStorage', 'sessionStorage', 'memory'], enableAutoDowngrade: true, defaultNamespace: 'default', enableLRUCache: true, lruCacheSize: 100, enableLock: true, lockTimeout: 5000, enableLogger: true, enableCrypto: false, enableValidation: false, defaultExpire: null, indexeddb: { dbName: 'enterprise-store', storeName: 'data', version: 1, }, }; /** * 配置管理器 */ export class ConfigManager { private static instance: ConfigManager; private config: StoreGlobalConfig; private constructor() { this.config = { ...defaultConfig }; } /** * 获取单例实例 */ public static getInstance(): ConfigManager { if (!ConfigManager.instance) { ConfigManager.instance = new ConfigManager(); } return ConfigManager.instance; } /** * 获取当前配置 */ public getConfig(): StoreGlobalConfig { return { ...this.config }; } /** * 更新运行时配置 * @param newConfig 新配置 */ public updateConfig(newConfig: RuntimeConfig): void { this.config = { ...this.config, ...newConfig }; } /** * 重置配置到默认值 */ public resetConfig(): void { this.config = { ...defaultConfig }; } /** * 获取指定引擎的优先级 * @param engineName 引擎名称 */ public getEnginePriority(engineName: string): number { return this.config.enginePriority.indexOf(engineName); } } // 导出全局配置实例 export const configManager = ConfigManager.getInstance();

命名空间NamespaceManager.ts

ts
/** * 命名空间管理器 - 避免key冲突 */ export class NamespaceManager { private readonly separator = '::'; /** * 生成带命名空间的键 * @param namespace 命名空间 * @param key 原始键 */ getNamespacedKey(namespace: string, key: string): string { if (!namespace) return key; return `${namespace}${this.separator}${key}`; } /** * 从带命名空间的键中提取原始键 * @param namespacedKey 带命名空间的键 * @param namespace 命名空间 */ extractOriginalKey(namespacedKey: string, namespace: string): string { if (!namespace) return namespacedKey; const prefix = `${namespace}${this.separator}`; return namespacedKey.startsWith(prefix) ? namespacedKey.slice(prefix.length) : namespacedKey; } /** * 过滤指定命名空间的键 * @param keys 所有键 * @param namespace 命名空间 */ filterNamespaceKeys(keys: string[], namespace: string): string[] { if (!namespace) return keys; const prefix = `${namespace}${this.separator}`; return keys .filter(key => key.startsWith(prefix)) .map(key => this.extractOriginalKey(key, namespace)); } /** * 检查键是否属于指定命名空间 * @param key 键 * @param namespace 命名空间 */ isInNamespace(key: string, namespace: string): boolean { if (!namespace) return true; return key.startsWith(`${namespace}${this.separator}`); } /** * 获取命名空间 * @param namespacedKey 带命名空间的键 */ getNamespace(namespacedKey: string): string { const parts = namespacedKey.split(this.separator); return parts.length > 1 ? parts[0] : ''; } } // 全局实例 export const namespaceManager = new NamespaceManager();

工具函数

batch.ts
/** * 批量操作优化器 * @param operation 要执行的批量操作 * @param batchSize 批次大小 * @returns 操作结果 */ export async function batchOptimize<T>( operation: () => Promise<T>, batchSize: number = 100 ): Promise<T> { // 性能监控 const startTime = performance.now(); try { // 执行操作 const result = await operation(); // 记录性能 const duration = performance.now() - startTime; if (duration > 100) { // 超过100ms的操作记录警告 console.warn(`Batch operation took ${duration.toFixed(2)}ms, consider optimizing batch size`); } return result; } catch (error) { console.error('Batch operation failed:', error); throw error; } } /** * 分割数组为批次 * @param array 原始数组 * @param batchSize 批次大小 * @returns 批次数组 */ export function splitIntoBatches<T>(array: T[], batchSize: number = 100): T[][] { const batches: T[][] = []; for (let i = 0; i < array.length; i += batchSize) { batches.push(array.slice(i, i + batchSize)); } return batches; } /** * 并行执行批次操作 * @param batches 批次数组 * @param handler 批次处理函数 * @returns 合并的结果 */ export async function executeBatches<T, R>( batches: T[][], handler: (batch: T[]) => Promise<R[]> ): Promise<R[]> { const results: R[][] = []; // 并行执行所有批次 const promises = batches.map(batch => handler(batch)); const batchResults = await Promise.allSettled(promises); // 处理结果 for (const result of batchResults) { if (result.status === 'fulfilled') { results.push(result.value); } else { console.error('Batch execution failed:', result.reason); results.push([]); } } // 合并结果 return results.flat(); }
downgrade.ts
import { engineRegistry } from "../core/registry/EngineRegistry"; import { configManager } from "../config/StoreConfig"; /** * 检查引擎是否支持 */ export async function checkEngineSupport(engineName: string): Promise<boolean> { const EngineConstructor = engineRegistry.getEngine(engineName); if (!EngineConstructor) { return false; } try { const engine = new EngineConstructor('__test__'); return await engine.testFunctionality(); } catch (error) { return false; } } /** * 获取降级引擎 */ export async function getFallbackEngine(preferredEngine: string): Promise<string | null> { const priority = configManager.getConfig().enginePriority; const preferredIndex = priority.indexOf(preferredEngine); // 从优先级列表中查找第一个支持的引擎 for (let i = preferredIndex + 1; i < priority.length; i++) { const engineName = priority[i]; if (await checkEngineSupport(engineName)) { return engineName; } } return null; }

类型守卫

type-guards.ts
/** * 类型守卫工具类 */ /** * 检查值是否为字符串 * @param value 要检查的值 */ export function isString(value: unknown): value is string { return typeof value === 'string' || value instanceof String; } /** * 检查值是否为数字 * @param value 要检查的值 */ export function isNumber(value: unknown): value is number { return typeof value === 'number' && !isNaN(value); } /** * 检查值是否为布尔值 * @param value 要检查的值 */ export function isBoolean(value: unknown): value is boolean { return typeof value === 'boolean'; } /** * 检查值是否为数组 * @param value 要检查的值 */ export function isArray(value: unknown): value is any[] { return Array.isArray(value); } /** * 检查值是否为对象 * @param value 要检查的值 */ export function isObject(value: unknown): value is Record<string, any> { return typeof value === 'object' && value !== null && !Array.isArray(value); } /** * 检查值是否为函数 * @param value 要检查的值 */ export function isFunction(value: unknown): value is Function { return typeof value === 'function'; } /** * 检查值是否为null * @param value 要检查的值 */ export function isNull(value: unknown): value is null { return value === null; } /** * 检查值是否为undefined * @param value 要检查的值 */ export function isUndefined(value: unknown): value is undefined { return typeof value === 'undefined'; } /** * 检查值是否为Date对象 * @param value 要检查的值 */ export function isDate(value: unknown): value is Date { return value instanceof Date && !isNaN(value.getTime()); } /** * 检查值是否为有效的JSON * @param value 要检查的值 */ export function isJsonString(value: string): boolean { try { JSON.parse(value); return true; } catch { return false; } } /** * 检查值是否为过期时间戳 * @param timestamp 时间戳 */ export function isExpired(timestamp: number | null): boolean { if (timestamp === null) return false; return Date.now() > timestamp; } /** * 类型断言函数 - 确保值不为null/undefined * @param value 要断言的值 * @param message 错误消息 */ export function assertExists<T>(value: T | null | undefined, message = 'Value must exist'): asserts value is T { if (value === null || value === undefined) { throw new Error(message); } }
index.ts
export * from './batch'; export * from './downgrade'; export * from './type-guards'; /** * 通用工具函数 */ /** * 生成唯一ID * @param prefix 前缀 */ export function generateId(prefix = 'store_'): string { return `${prefix}${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * 防抖函数 * @param func 要防抖的函数 * @param wait 等待时间 */ export function debounce<T extends (...args: any[]) => any>( func: T, wait: number ): (...args: Parameters<T>) => void { let timeout: number; return (...args: Parameters<T>) => { clearTimeout(timeout); timeout = setTimeout(() => func(...args), wait); }; } /** * 节流函数 * @param func 要节流的函数 * @param limit 限制时间 */ export function throttle<T extends (...args: any[]) => any>( func: T, limit: number ): (...args: Parameters<T>) => void { let lastCall = 0; return (...args: Parameters<T>) => { const now = Date.now(); if (now - lastCall >= limit) { lastCall = now; func(...args); } }; } /** * 深拷贝 * @param obj 要拷贝的对象 */ export function deepClone<T>(obj: T): T { if (obj === null || typeof obj !== 'object') { return obj; } if (obj instanceof Date) { return new Date(obj.getTime()) as T; } if (obj instanceof Array) { return obj.map(item => deepClone(item)) as T; } if (obj instanceof Object) { const clonedObj = {} as Record<string, any>; for (const key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = deepClone((obj as Record<string, any>)[key]); } } return clonedObj as T; } return obj; }

插件系统

加解密

type.ts
/** * 加密插件接口 */ export interface CryptoPlugin { /** * 加密数据 * @param data 原始数据 * @param key 加密密钥(可选) */ encrypt<T = any>(data: T, key?: string): Promise<string>; /** * 解密数据 * @param encryptedData 加密后的数据 * @param key 解密密钥(可选) */ decrypt<T = any>(encryptedData: string, key?: string): Promise<T>; /** * 设置默认密钥 * @param key 密钥 */ setDefaultKey(key: string): void; /** * 获取插件信息 */ getInfo(): { name: string; version: string }; }
DefaultCrypto.ts
// src/plugins/crypto/DefaultCrypto.ts import type { CryptoPlugin } from "./types"; /** * 默认加密插件 - 使用AES加密 */ export class DefaultCrypto implements CryptoPlugin { private defaultKey = 'enterprise-store-default-key'; /** * 简单的加密实现(生产环境建议使用更安全的加密方式) */ async encrypt<T = any>(data: T, key?: string): Promise<string> { const secretKey = key || this.defaultKey; const jsonString = JSON.stringify(data); // 简单的XOR加密(仅示例,生产环境请使用Web Crypto API) let encrypted = ''; for (let i = 0; i < jsonString.length; i++) { encrypted += String.fromCharCode( jsonString.charCodeAt(i) ^ secretKey.charCodeAt(i % secretKey.length) ); } return btoa(encrypted); } /** * 解密 */ async decrypt<T = any>(encryptedData: string, key?: string): Promise<T> { const secretKey = key || this.defaultKey; const decoded = atob(encryptedData); // XOR解密 let decrypted = ''; for (let i = 0; i < decoded.length; i++) { decrypted += String.fromCharCode( decoded.charCodeAt(i) ^ secretKey.charCodeAt(i % secretKey.length) ); } return JSON.parse(decrypted); } /** * 设置默认密钥 */ setDefaultKey(key: string): void { this.defaultKey = key; } /** * 获取插件信息 */ getInfo(): { name: string; version: string } { return { name: 'DefaultCrypto', version: '1.0.0' }; } }

日志

type.ts
/** * 日志级别 */ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; /** * 日志条目 */ export interface LogEntry { timestamp: number; level: LogLevel; operation: 'get' | 'set' | 'delete' | 'clear' | 'sweep' | 'batch' | 'test' | 'other' | 'keys' | 'has'; key?: string | string[]; namespace: string; engine: string; duration?: number; // 操作耗时(ms) success: boolean; error?: Error; metadata?: Record<string, any>; } /** * 日志插件接口 */ export interface LoggerPlugin { /** * 记录日志 * @param entry 日志条目 */ log(entry: LogEntry): Promise<void>; /** * 设置日志级别 * @param level 日志级别 */ setLogLevel(level: LogLevel): void; /** * 获取日志级别 */ getLogLevel(): LogLevel; /** * 上报错误 * @param error 错误对象 * @param context 上下文信息 */ reportError(error: Error, context?: Record<string, any>): Promise<void>; /** * 获取插件信息 */ getInfo(): { name: string; version: string }; }
DefaultLogger.ts
// src/plugins/logger/DefaultLogger.ts import type{ LoggerPlugin, LogEntry, LogLevel } from "./types"; /** * 默认日志插件 */ export class DefaultLogger implements LoggerPlugin { private logLevel: LogLevel = 'info'; private logs: LogEntry[] = []; private maxLogs = 1000; /** * 记录日志 */ async log(entry: LogEntry): Promise<void> { // 根据日志级别过滤 const levels: LogLevel[] = ['debug', 'info', 'warn', 'error', 'fatal']; if (levels.indexOf(entry.level) < levels.indexOf(this.logLevel)) { return; } // 存储日志 this.logs.push(entry); // 限制日志数量 if (this.logs.length > this.maxLogs) { this.logs.shift(); } // 控制台输出 const logMessage = `[${new Date(entry.timestamp).toISOString()}] [${entry.level}] [${entry.engine}] [${entry.operation}] ${entry.success ? 'SUCCESS' : 'FAILED'} ${entry.key ? `(key: ${Array.isArray(entry.key) ? entry.key.join(',') : entry.key})` : ''}`; switch (entry.level) { case 'debug': console.debug(logMessage, entry); break; case 'info': console.info(logMessage, entry); break; case 'warn': console.warn(logMessage, entry); break; case 'error': case 'fatal': console.error(logMessage, entry.error || entry); break; } } /** * 设置日志级别 */ setLogLevel(level: LogLevel): void { this.logLevel = level; } /** * 获取日志级别 */ getLogLevel(): LogLevel { return this.logLevel; } /** * 上报错误 */ async reportError(error: Error, context?: Record<string, any>): Promise<void> { // 这里可以集成错误监控平台,如Sentry、Fundebug等 console.error('Error reported:', error, context); // 记录错误日志 await this.log({ timestamp: Date.now(), level: 'error', operation: 'other', namespace: context?.namespace || 'unknown', engine: context?.engine || 'unknown', success: false, error, metadata: context }); } /** * 获取插件信息 */ getInfo(): { name: string; version: string } { return { name: 'DefaultLogger', version: '1.0.0' }; } /** * 获取日志记录 */ getLogs(): LogEntry[] { return [...this.logs]; } /** * 清空日志 */ clearLogs(): void { this.logs = []; } }

校验

type.ts
/** * 校验结果 */ export interface ValidationResult { valid: boolean; errors?: string[]; } /** * 校验插件接口 */ export interface ValidatorPlugin { /** * 校验数据 * @param data 要校验的数据 * @param schema 校验规则 */ validate<T = any>(data: T, schema: any): Promise<ValidationResult>; /** * 获取插件信息 */ getInfo(): { name: string; version: string }; }
ZodValidator.ts
// src/plugins/validator/ZodValidator.ts import { z, ZodSchema } from 'zod'; import type{ ValidatorPlugin, ValidationResult } from "./types"; /** * Zod校验插件 */ export class ZodValidator implements ValidatorPlugin { /** * 校验数据 */ async validate<T = any>(data: T, schema: ZodSchema): Promise<ValidationResult> { try { const result = schema.safeParse(data); if (result.success) { return { valid: true }; } else { return { valid: false, errors: result.error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}` ) }; } } catch (error) { return { valid: false, errors: [error instanceof Error ? error.message : 'Unknown validation error'] }; } } /** * 获取插件信息 */ getInfo(): { name: string; version: string } { return { name: 'ZodValidator', version: '1.0.0' }; } }

react/vue 适配

type.ts
/** * 响应式插件通用接口 */ export interface ReactivePlugin { /** * 创建响应式存储 * @param key 存储键 * @param initialValue 初始值 */ createReactiveStorage<T = any>(key: string, initialValue: T): ReactiveStorage<T>; } /** * 响应式存储接口 */ export interface ReactiveStorage<T = any> { /** * 响应式值 */ value: T; /** * 设置值 * @param value 新值 * @param expire 过期时间 */ set(value: T, expire?: number): Promise<boolean>; /** * 删除值 */ remove(): Promise<boolean>; /** * 刷新值 */ refresh(): Promise<void>; /** * 销毁响应式存储 */ destroy(): void; }

React Hooks

ts
import { useState, useEffect, useCallback } from 'react'; import { EnterpriseStore } from '../../core/Store'; /** * React响应式Hook */ export function useStorage<T = any>( store: EnterpriseStore, key: string, initialValue: T, schema?: any ): [T, (value: T, expire?: number) => Promise<boolean>, () => Promise<boolean>] { // 初始化状态 const [value, setValue] = useState<T>(initialValue); // 加载数据 useEffect(() => { async function loadData() { const data = await store.get<T>(key, schema); if (data !== null) { setValue(data); } } loadData(); // TODO: 可以实现监听存储变化的逻辑 const listener = (e: StorageEvent) => { if (e.key === key) { loadData(); } }; window.addEventListener('storage', listener); return () => window.removeEventListener('storage', listener); }, [store, key, schema]); // 设置值的函数 const setStoredValue = useCallback(async (newValue: T, expire?: number) => { const success = await store.set(key, newValue, expire, schema); if (success) { setValue(newValue); } return success; }, [store, key, schema]); // 删除值的函数 const removeStoredValue = useCallback(async () => { const success = await store.delete(key); if (success) { setValue(initialValue); } return success; }, [store, key, initialValue]); return [value, setStoredValue, removeStoredValue]; }

Vue Hooks

ts
import { ref, watch, onMounted } from 'vue'; import type{ Ref } from 'vue'; import { EnterpriseStore } from '../../core/Store'; // 定义返回类型接口 interface UseStorageReturn<T> { value: Ref<T>; set: (newValue: T, expire?: number) => Promise<boolean>; remove: () => Promise<boolean>; load: () => Promise<void>; } /** * Vue响应式Composable */ export function useStorage<T = any>( store: EnterpriseStore, key: string, initialValue: T, schema?: any ): UseStorageReturn<T> { const value = ref<T>(initialValue) as Ref<T>; // 加载数据 const load = async () => { const data = await store.get<T>(key, schema); if (data !== null) { value.value = data; } }; // 设置值 const set = async (newValue: T, expire?: number) => { const success = await store.set(key, newValue, expire, schema); if (success) { value.value = newValue; } return success; }; // 删除值 const remove = async () => { const success = await store.delete(key); if (success) { value.value = initialValue; } return success; }; // 初始化加载 onMounted(() => { load(); // TODO: 实现监听逻辑 window.addEventListener('storage', (e) => { if (e.key === key) { load(); } }); }); // 双向绑定 watch(value, (newValue) => { store.set(key, newValue, undefined, schema); }, { deep: true }); return { value, set, remove, load }; }

index.ts

ts
// 核心接口 export * from './core/interfaces/IStore'; // 主存储类 export { EnterpriseStore } from './core/Store'; // 配置管理 export * from './config'; // 存储引擎 export { MemoryEngine } from './core/engine/MemoryEngine'; export { LocalStorageEngine } from './core/engine/LocalStorageEngine'; export { SessionStorageEngine } from './core/engine/SessionStorageEngine'; export { IndexedDBEngine } from './core/engine/IndexedDBEngine'; // 引擎注册 export { engineRegistry } from './core/registry/EngineRegistry'; // 插件 export * from './plugins/crypto'; export * from './plugins/logger'; export * from './plugins/validator'; export * from './plugins/reactive'; // 工具函数 export * from './utils'; // 初始化默认引擎 import { engineRegistry } from './core/registry/EngineRegistry'; import { MemoryEngine } from './core/engine/MemoryEngine'; import { LocalStorageEngine } from './core/engine/LocalStorageEngine'; import { SessionStorageEngine } from './core/engine/SessionStorageEngine'; import { IndexedDBEngine } from './core/engine/IndexedDBEngine'; import { EnterpriseStore } from './core/Store'; // 注册默认引擎 engineRegistry.registerEngine('memory', MemoryEngine); engineRegistry.registerEngine('localStorage', LocalStorageEngine); engineRegistry.registerEngine('sessionStorage', SessionStorageEngine); engineRegistry.registerEngine('indexeddb', IndexedDBEngine); // 默认导出 export default EnterpriseStore;

example.ts

ts
import { EnterpriseStore, DefaultCrypto, DefaultLogger, ZodValidator } from './index'; import { z } from 'zod'; // 正确的使用方式 async function initStore() { // 1. 异步创建存储实例(关键修改) const store = await EnterpriseStore.create({ namespace: 'my-app', engine: 'indexeddb', config: { enableAutoDowngrade: true, enableLRUCache: true, lruCacheSize: 200, enableCrypto: true, enableValidation: true, enableLogger: true }, cryptoPlugin: new DefaultCrypto(), loggerPlugin: new DefaultLogger(), validatorPlugin: new ZodValidator(), encryptionKey: 'my-secret-key-123' }); // 2. 定义数据校验规则 const userSchema = z.object({ id: z.string().uuid(), name: z.string().min(2), age: z.number().int().positive() }); // 3. 执行存储操作 await store.set( 'user:123', { id: '123e4567-e89b-12d3-a456-426614174000', name: '张三', age: 25 }, 86400000, // 24小时过期 userSchema ); const user = await store.get('user:123', userSchema); console.log(user); return store; } // 初始化并使用存储 initStore().catch(console.error);
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:繁星

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!