如何threejs利用indexeddb緩存加載glb模型
threejs利用indexeddb緩存加載glb模型
有個(gè)坑,時(shí)不時(shí)的下載文件會(huì)遇到206錯(cuò)誤。
用axios的時(shí)候啊 responseType: 'blob’下載不一定會(huì)成功。
與文件的格式與編碼有關(guān)系。
后面我就換成fetch方式了,但fetch的blob()爭(zhēng)對(duì)所有文件下載也不是都成功,比如json文件得用json(),還有一些編碼為gbk格式的用Blob()也不一定回成功,用arraybuffer();
1、加載工具類(lèi) 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;
// 假如已經(jīng)有緩存了 直接用緩存
if (modelFile) {
if (onProgress) {
onProgress(100);
}
resolve(modelFile.blob)
} else {
// 假如沒(méi)有緩存 請(qǐng)求新的模型存入
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('請(qǐng)求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數(shù)據(jù)添加成功');
resolve(obj.blob);
};
inputRequest.onerror = function(evt) {
console.log('glb數(shù)據(jù)添加失敗', 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轉(zhuǎn)成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
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Javascript實(shí)現(xiàn)顏色rgb與16進(jìn)制轉(zhuǎn)換的方法
這篇文章主要介紹了Javascript實(shí)現(xiàn)顏色rgb與16進(jìn)制轉(zhuǎn)換的方法,實(shí)例分析了顏色值轉(zhuǎn)換的常用技巧與使用方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04
原生js實(shí)現(xiàn)簡(jiǎn)單貪吃蛇小游戲
這篇文章主要為大家詳細(xì)介紹了原生js實(shí)現(xiàn)貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
微信小程序接入微信支付實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了微信小程序接入微信支付實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-12-12
ExtJs的Ext.Ajax.request實(shí)現(xiàn)waitMsg等待提示效果
這篇文章主要介紹了ExtJs的Ext.Ajax.request實(shí)現(xiàn)waitMsg等待提示效果,需要的朋友可以參考下2017-06-06
Bootstrap 網(wǎng)站實(shí)例之單頁(yè)營(yíng)銷(xiāo)網(wǎng)站
這篇文章主要介紹了Bootstrap 網(wǎng)站實(shí)例之單頁(yè)營(yíng)銷(xiāo)網(wǎng)站的相關(guān)資料,本文給大家介紹的非常詳細(xì)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10
javascript實(shí)現(xiàn)了照片拖拽點(diǎn)擊置頂?shù)恼掌瑝Υa
這篇文章主要介紹了javascript實(shí)現(xiàn)了照片拖拽點(diǎn)擊置頂?shù)恼掌瑝Υa,效果非常不錯(cuò),這里推薦給大家,有需要的小伙伴可以參考下。2015-04-04
javascript用rem來(lái)做響應(yīng)式開(kāi)發(fā)
這篇文章主要介紹了javascript用rem來(lái)做響應(yīng)式開(kāi)發(fā),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
實(shí)用又漂亮的BootstrapValidator表單驗(yàn)證插件
這篇文章主要為大家詳細(xì)介紹了好用又漂亮的BootstrapValidator表單驗(yàn)證插件,感興趣的小伙伴們可以參考一下2016-05-05

