JS/TS 清空数组的几种方法比较


方式1:splice函数
arrayObject.splice(index,howmany,element1,…,elementX)

index:必选,规定从何处添加/删除元素。

howmany:必选,规定应该删除多少元素。未规定此参数,则删除从 index 开始到原数组结尾的所有元素。

element1:可选,规定要添加到数组的新元素。

var arr = [1,2,3,4];  
arr.splice(0,arr.length);  


方式2:给数组的length赋值为0
赋予数组的长度小于本身的长度,数组中后面的元素将被截断。

赋予数组的长度大于本身的长度,将扩展数组长度,多的元素为undefined。

var arr = [1,2,3,4];  
arr.length = 0;


方式3:直接赋予新数组 []
这种方式为将arr重新复制为空数组,之前的数组如果没有被引用,将等待垃圾回收。

var arr = [1,2,3,4];  
arr = [];


效率比较:
效率测试代码如下:

    var a = [];
    var b = [];
    var c = [];
    for(var i =0 ; i < 100000000;i++){
        a.push(i);
    }
    console.time('splice');
    a.splice(0,a.length); 
    console.timeEnd('splice');
    
    for(var i =0 ; i < 100000000;i++){
        b.push(i);
    }
    console.time('length');
    b.length = 0;
    console.timeEnd('length');
    
    for(var i =0 ; i < 100000000;i++){
        c.push(i);
    }
    console.time('赋值[]');
    c = [];
    console.timeEnd('赋值[]');


复制代码
测试结果:

splice: 0.010986328125ms
length: 0.009033203125ms
赋值[]: 0.024169921875ms

总结:
多次测试发现第二种方式最快,第一种其次,大数据量下 第三种最慢。

测试结果可能不严谨。大家仅做参考。


————————————————
原文链接:https://blog.csdn.net/qq_37904209/article/details/114598488

/* 文件路径: data/DataManager.js */ // @ts-nocheck // 导入依赖 import { LazyLoader } from './LazyLoader.js'; import { TransactionApi } from './TransactionApi.js'; import { IndexedDBManager } from './IndexedDBManager.js'; // 确保SockJS和Stomp库已加载 if (typeof SockJS === 'undefined') { throw new Error('SockJS library is required but not loaded. Please include it in your HTML.'); } if (typeof Stomp === 'undefined') { throw new Error('Stomp library is required but not loaded. Please include it in your HTML.'); } //这个函数不许改,也禁止废话,属性名和其他命名都哼规范不会出现意外, function resolveDataReferences(data) { console.log(data) // 获取 data 对象的所有顶层键 const keys = Object.keys(data); // 遍历每个顶层键(如 users, posts 等) for (const key of keys) { const entities = data[key]; // 遍历该顶层键下的每个实体(如每个 user 或 post) for (const entity of entities) { // 遍历实体的每个属性 for (const attribute in entity) { if (entity?.hasOwnProperty(attribute)) { var trpe=attribute?.replace(/\d/g, ''); // 确保属性属于当前实体 if (Array.isArray(entity[attribute])) { if(data[trpe]==null){ trpe+="s" } // 如果属性是一个数组,则将数组中的每个 ID 替换为对应的实际对象 entity[attribute] = entity[attribute].map(item => data[trpe ]?.find(updateItem => updateItem?.id === item?.id) || item ); } else if (typeof entity[attribute] === "object" && entity[attribute] !== null) { // 如果属性是一个对象,则将其替换为对应的实际对象 entity[attribute] = data[trpe + "s"]?.find(updateItem => updateItem?.id === entity[attribute]?.id); } } } } } return data; } function resolveDataReference(entity,data) { console.log(entity) // // 遍历实体的每个属性 for (const attribute in entity) { if (entity?.hasOwnProperty(attribute)) { var trpe=attribute?.replace(/\d/g, ''); // 确保属性属于当前实体 if (Array.isArray(entity[attribute])) { if(data[trpe]==null){ trpe+="s" } // 如果属性是一个数组,则将数组中的每个 ID 替换为对应的实际对象 entity[attribute] = entity[attribute].map(item => data[trpe ]?.find(updateItem => updateItem?.id === item?.id) || item ); } else if (typeof entity[attribute] === "object" && entity[attribute] !== null) { // 如果属性是一个对象,则将其替换为对应的实际对象 entity[attribute] = data[trpe + "s"]?.find(updateItem => updateItem?.id === entity[attribute]?.id); } } } return entity; } /** * 数据管理器类 - Web版 * 基于小程序版MiniProgramDataManager重构 */ class DataManager { constructor(baseUrl = "../php_api/index.php") { this.baseUrl = baseUrl; this.debug = true; this.networkAvailable = true; this.isSyncing = false; this.lastSync = null; this.storageKey = 'webAppData'; // 初始化IndexedDB管理器 this.indexedDBManager = new IndexedDBManager('KuCunAppData', 1); this._rawData = this.createEmptyData(); this.lazyLoader = new LazyLoader(this); // 初始化回调对象,支持动态添加新的数据类型 this.callbacks = { all: [] }; // 创建事务API实例 this.Transaction = new TransactionApi(this); // 实体文本映射,支持动态添加 this.entiyeText = { bancai: '板材已存在', dingdan: '订单已存在', mupi: '木皮已存在', chanpin: '产品已存在', kucun: '已有库存记录', chanpin_zujian: '产品已有该组件', dingdan_bancai: '', zujian: '组件已定义过了', caizhi: '材质已定义过了', dingdan_chanpin: '订单下已有该产品', user: '' }; // 进度更新回调函数 this.onProgressUpdate = null; this.initNetwork(); // 优先从IndexedDB加载数据 this.loadDataFromIndexedDB(); this.initWebSocket(); } createEmptyData() { // 基础数据结构,其他类型会在数据加载时自动添加 return { bancais: [], dingdans: [], mupis: [], chanpins: [], kucuns: [], dingdan_bancais: [], chanpin_zujians: [], zujians: [], caizhis: [], dingdan_chanpins: [], users: [], jinhuos: [], _lastModified: null, _lastSync: null }; } get data() { // 创建数据访问代理,保持懒加载功能 const self = this; return new Proxy(this._rawData, { get: (target, prop) => { if (prop.startsWith('_')) { return target[prop]; } if (Array.isArray(target[prop])) { // 为数组中的每个对象创建懒加载代理 return target[prop].map(item => { if (typeof item === 'object' && item !== null) { // 获取实体类型(去掉末尾的s) const entityType = prop.replace(/s$/, ''); return self.lazyLoader.createProxy(item, entityType); } return item; }); } return target[prop]; }, set: (target, prop, value) => { // 允许内部修改,但给出警告 console.warn(`直接修改 data.${prop} 可能会影响数据一致性,建议使用 DataManager 的方法`); target[prop] = value; return true; }, deleteProperty: (target, prop) => { console.warn(`直接删除 data.${prop} 可能会影响数据一致性,建议使用 DataManager 的方法`); delete target[prop]; return true; } }); } /** * 初始化指定的实体类型数据 * @param {Array} entityTypes - 要初始化的实体类型数组 */ async initialize(entityTypes = []) { try { // 确保IndexedDB初始化完成 await this.indexedDBManager.init(); // 如果没有指定实体类型,使用默认的核心实体类型 if (entityTypes.length === 0) { entityTypes = ['bancai', 'dingdan', 'mupi', 'chanpin', 'kucun', 'user']; } // 初始化每个实体类型的数据 const totalTypes = entityTypes.length; let completedCount = 0; // 先尝试从本地数据获取最后更新时间 const lastSyncTime = await this.indexedDBManager.getMetadata('lastSyncTime'); for (const entityType of entityTypes) { // 先从IndexedDB加载数据 const localData = await this.loadEntityFromIndexedDB(entityType); if (localData && localData.length > 0) { this._rawData[`${entityType}s`] = localData; // 通知本地数据加载成功 if (this.onProgressUpdate) { this.onProgressUpdate(30); } } // 如果有网络连接,使用时间增量获取后端数据补全 if (this.networkAvailable) { await this.fetchEntityData(entityType, lastSyncTime); } completedCount++; // 更新整体进度 if (this.onProgressUpdate) { const progress = Math.min(90, Math.floor((completedCount / totalTypes) * 90)); this.onProgressUpdate(progress); } } this._rawData._lastSync = new Date().toISOString(); // 保存到IndexedDB await this.saveDataToIndexedDB(); // 通知初始化完成 if (this.onProgressUpdate) { this.onProgressUpdate(100); } return true; } catch (error) { console.error('初始化失败:', error); if (this._rawData._lastSync) return true; throw error; } } /** * 从IndexedDB加载单个实体类型数据 */ async loadEntityFromIndexedDB(entityType) { try { const collectionName = `${entityType}s`; const data = await this.indexedDBManager.getAll(collectionName); return data || []; } catch (error) { console.error(`从IndexedDB加载${entityType}数据失败:`, error); return []; } } /** * 解析集合中的数据引用 */ resolveDataReferencesForCollection(collectionName) { if (!this._rawData[collectionName]) return; const entities = this._rawData[collectionName]; for (const entity of entities) { // 为每个实体解析引用 resolveDataReference(entity, this._rawData); } } /** * 初始化WebSocket连接 */ initWebSocket() { try { // 构建WebSocket URL(注意:SockJS需要使用HTTP或HTTPS协议而不是WS或WSS) const wsProtocol = window.location.protocol === 'https:' ? 'https:' : 'http:'; const wsHost = window.location.host; const wsUrl = `${wsProtocol}//${wsHost}/ws`; // 使用SockJS客户端 this.socket = new SockJS(wsUrl); this.stompClient = Stomp.over(this.socket); // 配置WebSocket连接 this.stompClient.connect({}, () => { console.log('WebSocket连接成功'); // 订阅实体更新主题 this.stompClient.subscribe('/topic/entity-updates', (message) => { this.handleWebSocketMessage(message); }); }, (error) => { console.error('WebSocket连接失败:', error); // 连接失败时尝试重新连接 setTimeout(() => this.initWebSocket(), 5000); }); // 监听连接关闭事件 this.socket.onclose = () => { console.log('WebSocket连接已关闭'); // 连接关闭时尝试重新连接 setTimeout(() => this.initWebSocket(), 5000); }; } catch (error) { console.error('WebSocket初始化失败:', error); // 初始化失败时尝试重新初始化 setTimeout(() => this.initWebSocket(), 5000); } } /** * 处理WebSocket消息 */ async handleWebSocketMessage(message) { try { const updateData = JSON.parse(message.body); const { operation, entityType, id, entityData } = updateData; // 转换实体类型为复数形式(集合名) const collectionName = this.getCollectionName(entityType); if (collectionName) { // 确保集合存在 if (!this._rawData[collectionName]) { this._rawData[collectionName] = []; } if (operation === 'create' || operation === 'update') { // 添加或更新实体 const index = this._rawData[collectionName].findIndex(item => item.id === id); if (index >= 0) { this._rawData[collectionName][index] = entityData; } else { this._rawData[collectionName].push(entityData); } // 更新到IndexedDB await this.indexedDBManager.put(collectionName, entityData); } else if (operation === 'delete') { // 删除实体 this._rawData[collectionName] = this._rawData[collectionName].filter(item => item.id !== id); // 从IndexedDB删除 await this.indexedDBManager.delete(collectionName, id); } // 解析数据引用 this.resolveDataReferencesForCollection(collectionName); // 触发回调,包含数据刷新类型 this.triggerCallbacks(operation, collectionName, entityData); // 清除缓存 this.lazyLoader.clearCache(); // 保存最后更新时间 await this.indexedDBManager.setMetadata('lastSyncTime', new Date().toISOString()); } } catch (error) { console.error('处理WebSocket消息失败:', error); // 触发错误回调,包含错误信息 this.triggerCallbacks('websocket_error', 'all', { error: error.message }); } } /** * 获取实体类型对应的集合名 */ getCollectionName(entityType) { // 转换首字母为小写 const lowerCaseType = entityType.charAt(0).toLowerCase() + entityType.slice(1); // 检查LazyLoader中的映射表 return this.lazyLoader.entityToCollectionMap[lowerCaseType] || `${lowerCaseType}s`; } async initNetwork() { // Web环境默认网络可用 this.networkAvailable = navigator.onLine; // 监听网络状态变化 window.addEventListener('online', () => { this.networkAvailable = true; }); window.addEventListener('offline', () => { this.networkAvailable = false; }); } /** * 同步指定实体类型的数据 * @param {String} entityType - 实体类型 */ async syncEntityData(entityType) { if (this.isSyncing) return; this.isSyncing = true; try { const since = this._rawData._lastSync; const success = await this.fetchEntityData(entityType, since); if (success) { this.lazyLoader.clearCache(); await this.saveDataToIndexedDB(); this.triggerCallbacks('refresh', `${entityType}s`, this.data); } } catch (error) { console.error(`同步${entityType}数据失败:`, error); this.triggerCallbacks('sync_error', entityType, { error }); } finally { this.isSyncing = false; } } /** * 获取指定实体类型的数据 * @param {String} entityType - 实体类型 * @param {String} since - 上次同步时间 */ async fetchEntityData(entityType, since = null) { try { // 通知开始加载数据 if (this.onProgressUpdate) { this.onProgressUpdate(10); } const params = since ? { since } : {}; const url = since ? `${this.baseUrl}/all/${entityType}?since=${encodeURIComponent(since)}` : `${this.baseUrl}/all/${entityType}`; // 通知正在获取数据 if (this.onProgressUpdate) { this.onProgressUpdate(30); } const response = await fetch(url); if (!response.ok) throw new Error(`HTTP错误: ${response.status}`); // 通知数据获取成功 if (this.onProgressUpdate) { this.onProgressUpdate(50); } const result = await response.json(); if (result.status !== 200) throw new Error(result.text || 'API错误'); // 通知正在解析数据 if (this.onProgressUpdate) { this.onProgressUpdate(60); } const collectionName = `${entityType}s`; const entityData = result.data || []; // 处理解析到的数据 if (since) { // 增量更新 if (!this._rawData[collectionName]) { this._rawData[collectionName] = []; } entityData.forEach(newItem => { const index = this._rawData[collectionName].findIndex(item => item.id === newItem.id); if (index >= 0) { this._rawData[collectionName][index] = newItem; } else { this._rawData[collectionName].push(newItem); } // 更新到IndexedDB this.indexedDBManager.put(collectionName, newItem); }); } else { // 全量更新 this._rawData[collectionName] = entityData; // 更新到IndexedDB(先清空再添加) await this.indexedDBManager.clear(collectionName); if (entityData.length > 0) { await this.indexedDBManager.putAll(collectionName, entityData); } } // 确保回调数组存在 if (!this.callbacks[collectionName]) { this.callbacks[collectionName] = []; } // 解析数据引用 this.resolveDataReferencesForCollection(collectionName); // 通知数据保存完成 if (this.onProgressUpdate) { this.onProgressUpdate(100); } // 更新最后同步时间 await this.indexedDBManager.setMetadata('lastSyncTime', new Date().toISOString()); return true; } catch (error) { console.error(`获取${entityType}数据失败:`, error); this.triggerCallbacks('fetch_error', entityType, { error }); return false; } } /** * 同步所有已加载的实体类型数据 * 主要用于初始化完成后,按需同步特定实体 */ async syncData() { if (this.isSyncing) return; console.warn('syncData方法已不推荐使用,请使用syncEntityData方法指定要同步的实体类型'); // 获取所有已加载的实体类型 const entityTypes = []; for (const key in this._rawData) { if (!key.startsWith('_') && Array.isArray(this._rawData[key])) { // 从集合名转换为实体类型(去掉末尾的s) const entityType = key.replace(/s$/, ''); entityTypes.push(entityType); } } // 同步每个实体类型 for (const entityType of entityTypes) { await this.syncEntityData(entityType); } this._rawData._lastSync = new Date().toISOString(); await this.saveDataToIndexedDB(); } async fetchAll(since) { try { // 通知开始加载数据,设置初始进度为10% if (this.onProgressUpdate) { this.onProgressUpdate(10); } // 不使用app/all接口,而是通过循环调用单个实体接口 const defaultEntityTypes = ['bancai', 'dingdan', 'mupi', 'chanpin', 'kucun', 'user']; const totalTypes = defaultEntityTypes.length; let completedCount = 0; for (const entityType of defaultEntityTypes) { await this.fetchEntityData(entityType, since); completedCount++; // 更新整体进度 if (this.onProgressUpdate) { const progress = Math.min(90, Math.floor((completedCount / totalTypes) * 90)); this.onProgressUpdate(progress); } } // 通知数据获取完成 if (this.onProgressUpdate) { this.onProgressUpdate(100); } return true; } catch (error) { console.error('获取所有数据失败:', error); this.triggerCallbacks('fetch_error', 'all', { error }); // 不要抛出异常,继续处理其他实体类型 return false; } } registerCallback(entity, callback) { // 动态创建回调数组 if (!this.callbacks[entity]) { this.callbacks[entity] = []; } this.callbacks[entity].push(callback); } unregisterCallback(entity, callback) { const arr = this.callbacks[entity] || this.callbacks.all; const index = arr.indexOf(callback); if (index !== -1) arr.splice(index, 1); } triggerCallbacks(operation, entity, data) { // 触发所有回调 this.callbacks.all.forEach(cb => cb(operation, entity, data)); // 触发特定实体的回调 this.callbacks[entity]?.forEach(cb => cb(operation, data)); } async crudOperation(operation, entity, data) { try { const response = await fetch(`${this.baseUrl}/app/${operation}/${entity}`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data) }); if (!response.ok) throw new Error('Network response was not ok'); const result = await response.json(); if (result.status !== 200) throw new Error(result.text || 'API error'); const resultData = result.data || data; this.updateLocalData(operation, entity, resultData); this.triggerCallbacks(operation, entity, resultData); return resultData; } catch (error) { this.triggerCallbacks(`${operation}_error`, entity, { data, error }); throw error; } } async updateLocalData(operation, entity, data) { const key = `${entity}s`; // 确保集合存在 if (!this._rawData[key]) { this._rawData[key] = []; } // 确保回调数组存在 if (!this.callbacks[key]) { this.callbacks[key] = []; } const collection = this._rawData[key]; switch (operation) { case 'add': collection.push(resolveDataReference(data, this._rawData)); // 保存到IndexedDB await this.indexedDBManager.put(key, data); break; case 'update': const index = collection.findIndex(item => item.id === data.id); index >= 0 ? Object.assign(collection[index], data) : collection.push(resolveDataReference(data, this._rawData)); // 保存到IndexedDB await this.indexedDBManager.put(key, data); break; case 'delete': const deleteIndex = collection.findIndex(item => item.id === data.id); if (deleteIndex >= 0) collection.splice(deleteIndex, 1); // 从IndexedDB删除 await this.indexedDBManager.delete(key, data.id); break; } this._rawData._lastModified = new Date().toISOString(); this.lazyLoader.clearCache(); // 保存元数据 await this.indexedDBManager.setMetadata('lastSyncTime', new Date().toISOString()); } async loadDataFromIndexedDB() { try { await this.indexedDBManager.init(); // 获取所有实体类型 const entityTypes = ['bancai', 'dingdan', 'mupi', 'chanpin', 'kucun', 'dingdan_bancai', 'chanpin_zujian', 'zujian', 'caizhi', 'dingdan_chanpin', 'user', 'jinhuo']; // 从IndexedDB加载每个实体类型的数据 for (const entityType of entityTypes) { const collectionName = `${entityType}s`; const data = await this.indexedDBManager.getAll(collectionName); if (data && data.length > 0) { this._rawData[collectionName] = data; } } // 加载最后同步时间 const lastSyncTime = await this.indexedDBManager.getMetadata('lastSyncTime'); if (lastSyncTime) { this._rawData._lastSync = lastSyncTime; } } catch (error) { console.error('从IndexedDB加载数据失败:', error); } } async saveDataToIndexedDB() { try { // 保存每个实体类型的数据 for (const key in this._rawData) { if (!key.startsWith('_') && Array.isArray(this._rawData[key])) { const data = this._rawData[key]; if (data && data.length > 0) { // 先清空再添加 await this.indexedDBManager.clear(key); await this.indexedDBManager.putAll(key, data); } } } // 保存最后同步时间 this._rawData._lastSync = new Date().toISOString(); await this.indexedDBManager.setMetadata('lastSyncTime', this._rawData._lastSync); } catch (error) { console.error('保存数据到IndexedDB失败:', error); } } // 兼容旧代码,保留localStorage方法但内部使用IndexedDB loadDataFromStorage() { this.loadDataFromIndexedDB(); } saveDataToStorage() { this.saveDataToIndexedDB(); } // 移除循环引用的辅助方法 removeCircularReferences(obj, seen = new WeakSet()) { if (obj === null || typeof obj !== 'object') { return obj; } if (seen.has(obj)) { return {}; // 返回空对象而不是循环引用 } seen.add(obj); if (Array.isArray(obj)) { return obj.map(item => this.removeCircularReferences(item, seen)); } const result = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { result[key] = this.removeCircularReferences(obj[key], seen); } } return result; } checkDuplicate(entity, data) { switch (entity) { case 'bancai': return this._rawData.bancais.some(b => b.houdu === data.houdu && b.caizhi?.id === data.caizhi?.id && b.mupi1?.id === data.mupi1?.id && b.mupi2?.id === data.mupi2?.id ); case 'caizhi': return this._rawData.caizhis.some(c => c.name === data.name); case 'mupi': return this._rawData.mupis.some(m => m.name === data.name && m.you === data.you); case 'chanpin': return this._rawData.chanpins.some(c => c.bianhao === data.bianhao); case 'zujian': return this._rawData.zujians.some(z => z.name === data.name); case 'dingdan': return this._rawData.dingdans.some(d => d.number === data.number); case 'chanpin_zujian': return this._rawData.chanpin_zujians.some(cz => cz.chanpin?.id === data.chanpin?.id && cz.zujian?.id === data.zujian?.id ); case 'dingdan_chanpin': return this._rawData.dingdan_chanpins.some(dc => dc.dingdan?.id === data.dingdan?.id && dc.chanpin?.id === data.chanpin?.id ); case 'dingdan_bancai': return this._rawData.dingdan_bancais.some(db => db.dingdan?.id === data.dingdan?.id && db.chanpin?.id === data.chanpin?.id && db.zujian?.id === data.zujian?.id && db.bancai?.id === data.bancai?.id ); case 'user': return this._rawData.users.some(u => u.name === data.name); default: return false; } } async addEntity(entity, data) { // 检查重复数据 if (this.checkDuplicate(entity, data)) { const errorMsg = `${this.entiyeText[entity]}`; this.triggerCallbacks('duplicate_error', entity, { data, error: errorMsg }); throw new Error(errorMsg); } return this.crudOperation('add', entity, data); } async updateEntity(entity, data) { return this.crudOperation('update', entity, data); } async deleteEntity(entity, id) { return this.crudOperation('delete', entity, { id }); } /** * * @param {*} endpoint * @param {*} data * @returns */ async transactionalOperation(endpoint, data) { return this.Transaction.execute(endpoint, data); } // 动态获取数据的方法 getEntity(entityType) { const key = entityType.endsWith('s') ? entityType : `${entityType}s`; return this.data[key] || []; } // 保留原有的快捷获取方法 getDingdans() { return this.getEntity('dingdans'); } getBancais() { return this.getEntity('bancais'); } getChanpins() { return this.getEntity('chanpins'); } getZujians() { return this.getEntity('zujians'); } getKucuns() { return this.getEntity('kucuns'); } getUsers() { return this.getEntity('users'); } getCaizhis() { return this.getEntity('caizhis'); } getMupis() { return this.getEntity('mupis'); } getDingdanBancais() { return this.getEntity('dingdan_bancais'); } getJinhuos() { return this.getEntity('jinhuos'); } getChanpinZujians() { return this.getEntity('chanpin_zujians'); } getDingdanChanpins() { return this.getEntity('dingdan_chanpins'); } // 业务方法 getChanpinsForDingdan(dingdanId) { const dingdan = this._rawData.dingdans?.find(d => d?.id == dingdanId); if (!dingdan) return []; return (dingdan.dingdan_chanpin_list || []) .map(dc => dc.chanpin) .filter(c => c); } getZujiansForChanpin(chanpinId) { const chanpin = this._rawData.chanpins?.find(c => c?.id == chanpinId); if (!chanpin) return []; return (chanpin.chanpin_zujian_list || []) .map(cz => cz.zujian) .filter(z => z); } getShengchanXiaohaoRecords() { return this._rawData.jinhuos?.filter(jinhuo => jinhuo.the_type_of_operation === 2 && jinhuo.shuliang < 0 ) || []; } getShengchanStatistics() { const today = new Date().toISOString().split('T')[0]; const thisMonth = new Date().toISOString().substring(0, 7); const consumptionRecords = this.getShengchanXiaohaoRecords(); const todayConsumption = consumptionRecords .filter(record => record.date && record.date.startsWith(today)) .reduce((sum, record) => sum + Math.abs(record.shuliang), 0); const monthConsumption = consumptionRecords .filter(record => record.date && record.date.startsWith(thisMonth)) .reduce((sum, record) => sum + Math.abs(record.shuliang), 0); const pendingOrders = this._rawData.dingdans?.filter(dingdan => !dingdan.deleted && dingdan.zhuangtai !== '已完成' ).length || 0; const lowStockCount = this._rawData.kucuns?.filter(kucun => !kucun.deleted && kucun.shuliang < 10 ).length || 0; return { today_consumption: todayConsumption, month_consumption: monthConsumption, pending_orders: pendingOrders, low_stock_count: lowStockCount, total_records: consumptionRecords.length }; } } export { DataManager }; ================================================================================ /* 文件路径: data/IndexedDBManager.js */ /** * IndexedDB工具类 - 用于大数据存储 */ class IndexedDBManager { constructor(dbName = 'appData', version = 1) { this.dbName = dbName; this.version = version; this.db = null; this.collections = new Set(); } /** * 初始化数据库连接 */ async init() { return new Promise((resolve, reject) => { if (this.db) { resolve(this.db); return; } const request = indexedDB.open(this.dbName, this.version); request.onupgradeneeded = (event) => { const db = event.target.result; // 确保存储元数据的集合存在 if (!db.objectStoreNames.contains('metadata')) { db.createObjectStore('metadata', { keyPath: 'key' }); } }; request.onsuccess = (event) => { this.db = event.target.result; resolve(this.db); }; request.onerror = (event) => { console.error('IndexedDB初始化失败:', event.target.error); reject(event.target.error); }; }); } /** * 确保对象存储空间(集合)存在 */ async ensureCollection(collectionName) { if (this.collections.has(collectionName)) { return true; } const db = await this.init(); // 检查对象存储空间是否已存在 if (db.objectStoreNames.contains(collectionName)) { this.collections.add(collectionName); return true; } // 需要升级数据库来创建新的对象存储空间 return new Promise((resolve, reject) => { const newVersion = db.version + 1; const request = indexedDB.open(this.dbName, newVersion); request.onupgradeneeded = (event) => { const newDb = event.target.result; // 创建新的对象存储空间,假设ID字段名为'id' if (!newDb.objectStoreNames.contains(collectionName)) { newDb.createObjectStore(collectionName, { keyPath: 'id' }); } }; request.onsuccess = (event) => { this.db = event.target.result; this.collections.add(collectionName); resolve(true); }; request.onerror = (event) => { console.error(`创建集合${collectionName}失败:`, event.target.error); reject(event.target.error); }; }); } /** * 执行数据库事务 */ async transaction(collectionName, mode = 'readonly', callback) { await this.ensureCollection(collectionName); const db = await this.init(); return new Promise((resolve, reject) => { try { const transaction = db.transaction([collectionName], mode); const store = transaction.objectStore(collectionName); const result = callback(store); transaction.oncomplete = () => resolve(result); transaction.onerror = (event) => reject(event.target.error); } catch (error) { reject(error); } }); } /** * 存储单个实体 */ async put(collectionName, entity) { return this.transaction(collectionName, 'readwrite', (store) => { return store.put(entity); }); } /** * 存储多个实体 */ async putAll(collectionName, entities) { return this.transaction(collectionName, 'readwrite', (store) => { entities.forEach(entity => store.put(entity)); return entities.length; }); } /** * 获取单个实体 */ async get(collectionName, id) { return this.transaction(collectionName, 'readonly', (store) => { return store.get(id); }); } /** * 获取所有实体 */ async getAll(collectionName) { return this.transaction(collectionName, 'readonly', (store) => { return store.getAll(); }); } /** * 删除单个实体 */ async delete(collectionName, id) { return this.transaction(collectionName, 'readwrite', (store) => { return store.delete(id); }); } /** * 清空集合 */ async clear(collectionName) { return this.transaction(collectionName, 'readwrite', (store) => { return store.clear(); }); } /** * 获取集合中实体的数量 */ async count(collectionName) { return this.transaction(collectionName, 'readonly', (store) => { return store.count(); }); } /** * 查询实体 */ async query(collectionName, query) { return this.transaction(collectionName, 'readonly', (store) => { const results = []; const request = store.openCursor(); return new Promise((resolve, reject) => { request.onsuccess = (event) => { const cursor = event.target.result; if (cursor) { // 执行查询条件 if (!query || this.matchesQuery(cursor.value, query)) { results.push(cursor.value); } cursor.continue(); } else { resolve(results); } }; request.onerror = (event) => { reject(event.target.error); }; }); }); } /** * 检查实体是否匹配查询条件 */ matchesQuery(entity, query) { for (const key in query) { if (entity[key] !== query[key]) { return false; } } return true; } /** * 存储元数据 */ async setMetadata(key, value) { return this.put('metadata', { key, value }); } /** * 获取元数据 */ async getMetadata(key) { const metadata = await this.get('metadata', key); return metadata ? metadata.value : null; } /** * 关闭数据库连接 */ close() { if (this.db) { this.db.close(); this.db = null; } } /** * 删除整个数据库 */ async deleteDatabase() { return new Promise((resolve, reject) => { this.close(); const request = indexedDB.deleteDatabase(this.dbName); request.onsuccess = () => resolve(true); request.onerror = (event) => reject(event.target.error); }); } } export { IndexedDBManager }; ================================================================================ /* 文件路径: data/LazyLoader.js */ /** * 懒加载器 - Web版 (优化版) * 修复了缓存键设计、集合名解析和数组处理问题 */ class LazyLoader { constructor(dataManager) { this.dataManager = dataManager; // 使用WeakMap避免内存泄漏 this.proxyCache = new WeakMap(); // 实体名到集合名的映射表 this.entityToCollectionMap = { bancai: 'bancais', dingdan: 'dingdans', mupi: 'mupis', chanpin: 'chanpins', kucun: 'kucuns', chanpin_zujian: 'chanpin_zujians', dingdan_bancai: 'dingdan_bancais', zujian: 'zujians', caizhi: 'caizhis', dingdan_chanpin: 'dingdan_chanpins', user: 'users', jinhuo: 'jinhuos' }; } /** * 清除缓存 */ clearCache() { this.proxyCache = new WeakMap(); } /** * 创建数据代理 * @param {Object} item - 原始数据项 * @param {string} entityType - 实体类型 * @returns {Proxy} 代理对象 */ createProxy(item, entityType) { // 非对象直接返回 if (!item || typeof item !== 'object') return item; // 检查是否已有代理 if (this.proxyCache.has(item)) { return this.proxyCache.get(item); } const proxy = new Proxy(item, { get: (target, prop) => { // 直接返回基本属性 if (typeof prop === 'symbol' || prop.startsWith('_') || typeof target[prop] !== 'object') { return target[prop]; } const value = target[prop]; // 处理null值 if (value === null) return null; // 处理数组关联 if (Array.isArray(value)) { return value.map(relatedItem => this.resolveRelation(relatedItem, prop) ); } // 处理对象关联 else if (typeof value === 'object') { return this.resolveRelation(value, prop); } return value; }, set: (target, prop, value) => { target[prop] = value; return true; } }); // 缓存代理对象 this.proxyCache.set(item, proxy); return proxy; } /** * 解析关联对象 * @param {Object|string|number} relatedItem - 关联项 * @param {string} propName - 关联属性名 * @returns {Object} 解析后的关联对象 */ resolveRelation(relatedItem, propName) { // 基本类型直接返回 if (typeof relatedItem !== 'object' || relatedItem === null) { return relatedItem; } // 去掉数字后缀 (如 mupi1 → mupi) const basePropName = propName.replace(/\d/g, ''); // 获取实体类型 let entityType; // 检查是否已在映射表中 if (this.entityToCollectionMap[basePropName]) { entityType = basePropName; } else { // 尝试从集合名反向查找实体类型 entityType = Object.keys(this.entityToCollectionMap).find( key => this.entityToCollectionMap[key] === basePropName ) || basePropName; } // 获取集合名 let collectionName; // 检查映射表中是否有对应的集合名 if (this.entityToCollectionMap[entityType]) { collectionName = this.entityToCollectionMap[entityType]; } else { // 动态处理新的实体类型,默认添加's'后缀 collectionName = `${entityType}s`; // 将新的映射关系添加到映射表中 this.entityToCollectionMap[entityType] = collectionName; } // 获取数据集合 const collection = this.dataManager._rawData[collectionName]; if (!collection) return relatedItem; // 查找完整对象 const fullItem = collection.find(item => item?.id === relatedItem?.id); if (!fullItem) return relatedItem; // 返回代理对象 return this.createProxy(fullItem, entityType); } } export { LazyLoader }; ================================================================================ /* 文件路径: data/TransactionApi.js */ /** * 事务API - Web版 * 负责处理所有事务相关的操作 */ class TransactionApi { constructor(dataManager) { this.dataManager = dataManager; this.baseUrl = dataManager.baseUrl; } /** * 执行事务操作 * @param {string} endpoint - 事务端点 * @param {Object} data - 事务数据 * @returns {Promise} 操作结果 */ async execute(endpoint, data) { try { const response = await fetch(`${this.baseUrl}/app/transactional/${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const result = await response.json(); if (result.status !== 200) { throw new Error(result.text || 'Transaction failed'); } // 在WebSocket模式下,数据会自动更新,无需手动同步 // 仅触发事务成功回调 this.dataManager.triggerCallbacks('transaction_success', endpoint, result.data); return result.data; } catch (error) { console.error(`Transaction ${endpoint} failed:`, error); // 触发事务失败回调 this.dataManager.triggerCallbacks('transaction_error', endpoint, { data, error: error.message }); throw error; } } /** * 库存编辑事务 * @param {Object} params - 事务参数 * @param {Number} params.kucunId - 库存ID * @param {Number} params.newStock - 新的库存数量 * @param {Number} params.oldStock - 原库存数量 * @param {String} params.note - 备注信息 * @param {Number} params.userId - 用户ID * @returns {Promise} 操作结果 */ async updateStock(params) { return this.execute('kucunbianji', params); } /** * 生产消耗事务 * @param {Object} params - 生产消耗参数 * @returns {Promise} 操作结果 */ async shengchanXiaohao(params) { return this.execute('shengchanXiaohao', params); } /** * 批量更新订单板材事务 * @param {Object} params - 批量更新参数 * @returns {Promise} 操作结果 */ async batchUpdateDingdanBancai(params) { return this.execute('batchUpdateDingdanBancai', params); } /** * 提交订单板材采购事务 * @param {Object} params - 提交参数 * @returns {Promise} 操作结果 */ async submitDingdanBancai(params) { return this.execute('submitDingdanBancai', params); } /** * 消耗订单板材事务 * @param {Object} params - 消耗参数 * @returns {Promise} 操作结果 */ async consumeDingdanBancai(params) { return this.execute('consumeDingdanBancai', params); } /** * 采购订单板材事务 * @param {Object} params - 采购参数 * @returns {Promise} 操作结果 */ async 采购DingdanBancai(params) { return this.execute('采购DingdanBancai', params); } /** * 保存所有数据事务 * @param {Object} params - 保存参数 * @returns {Promise} 操作结果 */ async saveAll(params) { try { const response = await fetch(`${this.baseUrl}/app/save-all`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const result = await response.json(); if (result.status !== 200) { throw new Error(result.text || 'Save all failed'); } // 在WebSocket模式下,数据会自动更新,无需手动同步 return result.data; } catch (error) { console.error('Save all failed:', error); throw error; } } } export { TransactionApi }; ----------------------------要和实际数据类型解耦,只要按命名规范命名的实体类型都可以用
09-21
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值