/** * 此工具类是对三维模型数据存储到浏览器indexDB的封装 * 【为什么使用indexDB存储三维模型数据】: * >> 由于微信浏览器glb模型的浏览器缓存不生效(服务器配置了强缓存和协商缓存,但每次还是需要重新拉取),出于用户体验优化的考虑,直接缓存到浏览器数据库中 * 【实践过程】: * 1. 最开始尝试直接存储加载glb的模型的json数据,无法直接存储 * 2. 其次尝试JSON.stringify转换成字符串,由于此方法原型链丢失,也无法直接使用 * 3. 最终采用blob类型存储实现 * 【如何使用?】参照如下: * const indexDB = new DBUtils(dbName, storeName, dbVersion) * indexDB.get(modelUrl).then(blob => { * const url = URL.createObjectURL(new Blob([blob])); * const loader = new GLTFLoader(); * loader.load(url, (gltf) => { * const root = gltf.scene * ...(下面部分就和threejs加载glb模型代码一样,按业务需求做相应的操作) * }, xhr => { * const {loaded, total } = xhr * console.log(`已加载${loaded / total * 100}%`) * }) */ export default class DBUtils { constructor(dbName, storeName, dbVersion = 1) { this.dbName = dbName; this.storeName = storeName; this.dbVersion = dbVersion; this.db = null; } async get(url) { this.db = await this.initDataBase(this.dbName, this.storeName, this.dbVersion); const request = this.db .transaction([this.storeName], 'readwrite') .objectStore(this.storeName) .get(url); return new Promise((resolve, reject) => { request.onsuccess = evt => { const modelFile = evt.target.result; // 如果缓存中有,直接从缓存中获取 if (modelFile) { resolve(modelFile.blob); } else { // 如果缓存中没有,则请求资源 this.addData(url).then(blob => { resolve(blob); }).catch(() => { reject(); }); } }; request.onerror = evt => { console.log('error', evt); reject(); }; }); } async addData(url) { // 如果使用vue,也可以用axios请求 const res = await fetch(url, { method: 'get' }); if (res.status == 200) { let blob = null; // 采用fetch的blob()并不是针对所有文件下载都成功,比如json文件得用json(),还有一些编码为gbk格式的用blob()也可能失败,所以采用arrayBuffer和blob兼容处理 try { blob = await res.arrayBuffer(); } catch (e) { // 采用arrayBuffer方式失败,改用blob方式 blob = await res.blob(); } const obj = { url, blob: new Blob([blob]) }; const request = this.db .transaction([this.storeName], 'readwrite') .objectStore(this.storeName) .add(obj); return new Promise((resolve, reject) => { request.onsuccess = () => { // 添加数据成功 resolve(obj.blob); }; request.onerror = evt => { console.log('添加数据失败', evt); reject(); }; }); } } initDataBase(dbName, storeName, dbVersion = 1) { if (!window.indexedDB) { console.log('您的浏览器不持支此版的IndexDB'); } else { const request = indexedDB.open(dbName, dbVersion); return new Promise((resolve, reject) => { request.onerror = () => { console.log('error: 创建db时出现异常'); reject(); }; request.onupgradeneeded = (evt) => { evt.currentTarget.result.createObjectStore(storeName, { keyPath: 'url' }); }; request.onsuccess = (evt) => { resolve(evt.target.result); }; }); } } }