threejs利用indexeddb缓存加载glb模型
有个坑,时不时的下载文件会遇到206错误。
用axios的时候啊 responsetype: 'blob’下载不一定会成功。
与文件的格式与编码有关系。
后面我就换成fetch方式了,但fetch的blob()争对所有文件下载也不是都成功,比如json文件得用json(),还有一些编码为gbk格式的用blob()也不一定回成功,用arraybuffer();
1、加载工具类 indexeddb.js
const db_name = 'daxue1'; const db_version = 1; // use a long long for this value (don't use a float) const db_store_name = 'model_glb'; export class dbutil { async get(url, onprogress) { this.db = await this.initdatabase(); let getrequest = this.db .transaction([db_store_name], "readwrite").objectstore(db_store_name).get(url); let that = this; return new promise((resolve, reject) => { getrequest.onsuccess = function (event) { let modelfile = event.target.result; // 假如已经有缓存了 直接用缓存 if (modelfile) { if (onprogress) { onprogress(100); } resolve(modelfile.blob) } else { // 假如没有缓存 请求新的模型存入 that.put(url, onprogress).then((blob) => { resolve(blob) }).catch(() => { reject() }); } }; getrequest.onerror = function (event) { console.log('error', event) reject() } }) } async put(url, onprogress) { const response = await fetch(url); if (response.status !== 200) { throw new error('request failed'); } const contentlength = response.headers.get('content-length'); console.log(contentlength) const totalbytes = parseint(contentlength, 10); let downloadedbytes = 0; const readablestream = response.body; const { readable, writable } = new transformstream(); const writer = writable.getwriter(); const reader = readablestream.getreader(); const pump = async () => { const { done, value } = await reader.read(); if (done) { writer.close(); return; } writer.write(value); downloadedbytes += value.length; if (onprogress) { const progress = (downloadedbytes / totalbytes) * 100; console.log(progress.tofixed(2)) onprogress(progress.tofixed(2)); } return pump(); }; await pump(); let blob = null; try { blob = await new response(readable).arraybuffer(); } catch (e) { console.log('请求arraybuffer失败,用blob方式') blob = await new response(readable).blob(); } let obj = { ssn: url } obj.blob = new blob([blob]) const inputrequest = this.db .transaction([db_store_name], "readwrite") .objectstore(db_store_name) .add(obj); return new promise((resolve, reject) => { inputrequest.onsuccess = function() { console.log('glb数据添加成功'); resolve(obj.blob); }; inputrequest.onerror = function(evt) { console.log('glb数据添加失败', evt); reject(); }; }); } initdatabase() { if (!window.indexeddb) { console.log("your browser doesn't support a stable version of indexeddb.") return; } let request = indexeddb.open(db_name, db_version); return new promise((resolve, reject) => { request.onerror = function () { console.log("error: create db error"); reject() }; request.onupgradeneeded = function (evt) { evt.currenttarget.result.createobjectstore( db_store_name, {keypath: 'ssn'}); }; request.onsuccess = function (evt) { console.log("onsuccess: create db success "); resolve(evt.target.result) }; }) } }
2、加载模型
let url = url.createobjecturl(new blob([blob]))
利用url.createobjecturl把blob转成load可加载的url
import * as three from 'three/build/three.module.js'; import { gltfloader } from 'three/examples/jsm/loaders/gltfloader.js'; import {dbutil} from "../util/dbutil"; let model = new three.group(); new dbutil().get('/droc_model/changsharelease.glb',(progress) => { console.log(progress) }).then((blob) => { console.log('getmodel获取成功', blob); let loader = new gltfloader(); let url = url.createobjecturl(new blob([blob])); loader.load(url, function (gltf) { model.add(gltf.scene); }, function ( xhr ) { console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' ); }) }) export { model }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论