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
}总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论