Threejs 模型本地存储
还是之前那个模型查看的问题,有个模型 50M,每次打开都需要从服务器上请求模型,速度太慢被老板吐槽了,所以考虑将模型存在本地,具体的方案呢,我选定了使用 IndexedDB
我的思路是这样的:
- 首先在 indexedDB 查找有没有这个模型的数据存在
- 如果存在就将这个数据查询出来,加载本地的模型
- 如果不存在就从服务器请求模型数据,然后存在本地 indexedDB
但是有两个问题:
- 从服务器请求到的模型怎么转换成 blob 存进 indexedDB
- threejs 的 gltfLoader 需要提供的是一个确切的 url 地址
开始解决问题:
首先解决怎么把从服务器请求到的模型转换成 blob
1 2 3 4 5 6 7
| axios({ url: url, method: 'get', responseType: 'blob', }).then((res) => { let blob = res.data })
|
然后我们把这个数据存进 IndexedDB:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| let id = 'xxxxx'
let indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB if (!indexedDB) { console.log('不支持indexedDB') }
let request = indexedDB.open('userModels') let db request.onupgradeneeded = (event) => { console.log('数据库更新') db = event.target.result if (!db.objectStoreNames.contains('models')) { let objectStore objectStore = db.createObjectStore('models', { keyPath: 'id', }) } } request.onsuccess = (event) => { db = event.target.result let transaction = db.transaction(['models'], 'readwrite') let objStore = transaction.objectStore('models') let req = objStore.get(id) req.onsuccess = (e) => { if (req.result) { console.log(req.result) } else { axios({ url: url, method: 'get', responseType: 'blob', }).then((res) => { let blob = res.data db.transaction(['models'], 'readwrite') .objectStore('models') .add({ id: id, blob: blob }) }) } } }
|
第二个问题,blob 怎么转换成 url
URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的 URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的 URL 对象表示指定的 File 对象或 Blob 对象。
1
| objectURL = URL.createObjectURL(object)
|
其中参数 object 是: 用于创建 URL 的 File 对象、Blob 对象或者 MediaSource 对象。
最终代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| function getRealUrl(id, url) { return new Promise((resolve, reject) => { let fileType = url.split('.')[url.split('.').length - 1] let indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB if (!indexedDB) { resolve(url) return false } let request = indexedDB.open('userModels') let db request.onupgradeneeded = (event) => { console.log('数据库更新') db = event.target.result if (!db.objectStoreNames.contains('models')) { let objectStore objectStore = db.createObjectStore('models', { keyPath: 'id', }) } } request.onsuccess = (event) => { console.log('数据库打开成功') db = event.target.result let transaction = db.transaction(['models'], 'readwrite') let objStore = transaction.objectStore('models') let req = objStore.get(id) req.onsuccess = (e) => { if (req.result) { console.log('已经查询到数据为:') console.log(req.result) let modelUrl = URL.createObjectURL(req.result.blob) db.close() resolve(modelUrl) } else { console.log('未查询到数据') axios({ url: url, method: 'get', responseType: 'blob', }) .then((res) => { let blob = res.data db.transaction(['models'], 'readwrite') .objectStore('models') .add({ id: id, blob: blob }) let modelUrl = URL.createObjectURL(blob) db.close() resolve(modelUrl) }) .catch(() => { db.close() resolve(url) }) } } } }) }
|