微信小程序開發(fā)過程中蔬墩,使用web-view標(biāo)簽引入H5頁面,會(huì)發(fā)現(xiàn)例如glb等三維模型文件拇颅,哪怕服務(wù)器設(shè)置了http緩存樟插,也不會(huì)生效,用戶每次打開頁面還是要重新加載三維模型黄锤,而一些三維模型的體積可能又會(huì)比較大,所以就考慮將3D模型緩存下來副编,經(jīng)過實(shí)踐嘗試后齿桃,封裝了用于處理此場景的函數(shù)工具類煮盼,希望能幫助需要做此塊改進(jìn)優(yōu)化的人。
/**
* 此工具類是對(duì)三維模型數(shù)據(jù)存儲(chǔ)到瀏覽器indexDB的封裝
* 【為什么使用indexDB存儲(chǔ)三維模型數(shù)據(jù)】:
* >> 由于微信瀏覽器glb模型的瀏覽器緩存不生效(服務(wù)器配置了強(qiáng)緩存和協(xié)商緩存香到,但每次還是需要重新拉取)悠就,出于用戶體驗(yàn)優(yōu)化的考慮,直接緩存到瀏覽器數(shù)據(jù)庫中
* 【實(shí)踐過程】:
* 1. 最開始嘗試直接存儲(chǔ)加載glb的模型的json數(shù)據(jù)梗脾,無法直接存儲(chǔ)
* 2. 其次嘗試JSON.stringify轉(zhuǎn)換成字符串炸茧,由于此方法原型鏈丟失梭冠,也無法直接使用
* 3. 最終采用blob類型存儲(chǔ)實(shí)現(xiàn)
* 【如何使用改备?】參照如下:
* 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模型代碼一樣,按業(yè)務(wù)需求做相應(yīng)的操作)
* }, xhr => {
* // 此處可以計(jì)算加載進(jìn)度
* 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 {
// 如果緩存中沒有默勾,則請(qǐng)求資源
this.addData(url).then(blob => {
resolve(blob);
}).catch(() => {
reject();
});
}
};
request.onerror = evt => {
console.log('error', evt);
reject();
};
});
}
async addData(url) {
// 如果使用vue灾测,也可以用axios請(qǐng)求
const res = await fetch(url, { method: 'get' });
if (res.status == 200) {
let blob = null;
// 采用fetch的blob()并不是針對(duì)所有文件下載都成功,比如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 = () => {
// 添加數(shù)據(jù)成功
resolve(obj.blob);
};
request.onerror = evt => {
console.log('添加數(shù)據(jù)失敗', 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: 創(chuàng)建db時(shí)出現(xiàn)異常');
reject();
};
request.onupgradeneeded = (evt) => {
evt.currentTarget.result.createObjectStore(storeName, {
keyPath: 'url'
});
};
request.onsuccess = (evt) => {
resolve(evt.target.result);
};
});
}
}
}