场景问题
最近在做大模型的加载,加载文件的时候会解析出这个文件有多少个mesh
, line
, parameter
, 而后都会存在一个变量中去保护这个关系:
const detailedList = { mesh: Array, line: Array, parameter: Array}
这样会导致这个内存吃紧,毕竟间接存了好几G的数据信息。
那还有一种说法是, 文件加载过去间接就渲染不就行了吗?
然而这样会导致DC
过多, CPU
吃不消。
IndexDB
应用indexDB
来充当一个相似内存
的性能, 我把数据选择性的存在indexDB中,须要的时候再拿,这样会大大缓解内存压力。indexDB相似NOSQL,并不是MYSQL这种二维表构造, 取数据的速度是飞快的。
结构一个Store
和大部分前端我的项目一样,我也结构了一个store.
enum StoreType { MEMORY, INDEXDB}class Store { /** * 寄存在内存中的数据 */ private memory: Map<string, any> private readonly dbVersion: number; /** * indexDB */ private db: IDBDatabase; private isReady: boolean; /** * 贮存的value多大才应用indexDB贮存,反之应用map */ private readonly limitForDB: number; /** * 达到贮存下限后一次性删除多少条数据 */ private readonly deleteCount: number; /** * 贮存下限 */ private readonly upperStorageLimit: number; constructor(dbVersion = 1, limitForDB?: number) { this.isReady = false this.dbVersion = dbVersion this.initIndexDB() this.memory = new Map() this.limitForDB = limitForDB || 30 this.upperStorageLimit = 10000 this.deleteCount = 20 } set(key: string, value: any, type?: StoreType) { const intoMemory = () => { this.memory.set(key, value) } const intoIndexDB = () => { const objectStore = this.getObjectStore(); objectStore.put({id: key, value}, key); this.calculationTimesAndDelete(); } if (typeof type !== 'undefined') { type === StoreType.INDEXDB ? intoIndexDB() : intoMemory() } else { if (Store.sizeOf(value) > this.limitForDB) { // indexDB加之前删除map中存在的key this.clear(key, StoreType.MEMORY) intoIndexDB() } else { // 退出map之前删除indexDB中存在的key this.clear(key, StoreType.INDEXDB) intoMemory() } } } get(key: string, type?: StoreType): Promise<any> { return new Promise((resolve, reject) => { const fromMemory = (key) => { resolve(this.memory.get(key)) } const fromIndexDB = (key) => { const objectStore = this.getObjectStore(); const index = objectStore.index("id"); const res = index.get(key); res.onsuccess = (e) => { // @ts-ignore resolve(e.target.result.value) } res.onerror = (e) => { reject(e) } } if (typeof type !== 'undefined') { type === StoreType.INDEXDB ? fromIndexDB(key) : fromMemory(key) } else { this.memory.has(key) ? fromMemory(key) : fromIndexDB(key) } }) } /** * 查询数据库条数 */ calculationTimesAndDelete() { const result = this.getObjectStore().count() result.onsuccess = (e) => { // @ts-ignore if (e.result > this.upperStorageLimit) { this.deleteFromPrevious() } } } /** * 达到阈值后删除最开始建设的数据 * @description 避免数据收缩 */ deleteFromPrevious() { const objectStore = this.getObjectStore() const request = objectStore.openCursor(); let count = 0 request.onsuccess = (event) => { // @ts-ignore const cursor = event.target.result if (cursor) { if (count === this.deleteCount) return; count++; objectStore.delete(cursor.key) cursor.continue() } } } getObjectStore() { const transaction = this.db.transaction(["store"], "readwrite"); return transaction.objectStore("store") } clear(key: string, type?: StoreType) { const fromMemoryDel = () => this.memory.delete(key) const fromIndexDBDel = () => { const objectStore = this.getObjectStore(); objectStore.delete(key) } if (typeof type !== 'undefined') { type === StoreType.INDEXDB ? fromIndexDBDel() : fromMemoryDel() } else { this.memory.has(key) ? fromMemoryDel() : fromIndexDBDel() } } initIndexDB() { // @ts-ignore const indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB if (!indexedDB) { alert('indexDB被浏览器禁止!') throw new Error('indexDB forbidden in the browser!') } const request = indexedDB.open("elephantFiles", this.dbVersion) request.onerror = function () { throw new Error('Error creating/accessing IndexedDB database'); } request.onsuccess = event => { // @ts-ignore this.db = event.target.result as IDBDatabase; this.isReady = true } request.onupgradeneeded = (event) => { console.log('database upgradeneeded!') // @ts-ignore const db = event.target.result as IDBDatabase; if (!db.objectStoreNames.contains('store')) { const store = db.createObjectStore('store') store.createIndex('id', 'id') } } } /** * @description 不确认是否初始化结束时 将查问赋值等操作包裹在此 */ ready(callback: Function) { const step = () => { if (this.isReady) { callback && callback() return; } window.requestAnimationFrame(step) } window.requestAnimationFrame(step) } /** * @description 估算字节大小, 疏忽key的长度, 如果是object只计算value, 比JSON.stringify更快 */ static sizeOf(value): number { const typeSizes = { "undefined": () => 0, "boolean": () => 4, "number": () => 8, "string": item => 2 * item.length, "object": item => !item ? 0 : Object .keys(item) .reduce((total, key) => size(key) + size(item[key]) + total, 0) }; const size = value => typeSizes[typeof value](value); return size(value) }}export {StoreType, Store}
应用
const a = new Store();a.ready(() => { a.set('a', { k: 'dsdsdsdsdssdsd', p: [123, 'sdsdsdsdsdsdsdvvvvvvvvv'] }) a.set('b', 123) a.get('b') a.get('a')})
依据客户的客户端条件适当调节limitForDB
和upperStorageLimit