預加載是在進入正式場景之前提前加載所需模型、材質、圖片等資源的技術手段,其核心價值在於消除資源加載等待,確保場景首次渲染即可完整呈現,從而提供無縫、流暢的用户體驗。在複雜的 Web 3D 可視化應用中,資源預加載尤為重要,可有效解決首次加載時的卡頓、白屏及交互延遲等問題。
預加載實現方案
基礎實現原理
HT for Web 中所有資源的請求都會經過 ht.Default.convertURL 方法,該方法提供了統一的資源請求入口:
- 當返回字符串路徑時,框架會按此路徑發起資源請求;
- 當返回 {data: content} 格式對象時,框架會直接使用 content 作為資源內容。
基於此特性,我們可實現預加載機制
// 資源緩存映射表
let sourceMap = {};
// 判斷是否為本地資源
functionisLocalUrl(url) {
return url.startsWith('data:') || url.startsWith('blob:');
}
// 重寫 convertURL 方法
let oldFunc = ht.Default.convertURL;
ht.Default.convertURL = function(url) {
if (isLocalUrl(url)) return url;
let source = sourceMap[url];
if (source) {
return { data: source };
}
return oldFunc(url);
};
資源加載策略
部分資源預加
適用於資源量較大但部分關鍵資源需要優先加載的場景。
// 關鍵資源列表
let resources = [
"models/model.json",
"assets/texture.png",
"symbols/symbols.json"
]
全量資源預加載
獲取所有已註冊資源進行預加載:
functiongetAllResources() {
return [
...Object.keys(ht.Default.getImageMap()),
...Object.keys(ht.Default.getCompTypeMap()),
...Object.keys(ht.Default.getShape3dModelMap()),
...Object.keys(ht.Default.getMaterialMap()),
...Object.keys(ht.Default.getHdrTextureMap())
];
}
let allResources = getAllResources();
資源加載實現
// 資源類型判斷
const ResourceType = {
IMAGE: /\.(png|jpg|gif|jpeg|bmp|svg)$/i,
BUFFER: /\.(fbx|gltf|glb)$/i,
HDR: /\.hdr$/i,
TGA: /\.tga$/i,
JSON: /\.json$/i
};
class ResourceLoader {
constructor(resources) {
this.resources = resources;
this.loaded = 0;
}
load() {
this.resources.forEach(url => {
if (ResourceType.BUFFER.test(url)) {
this.loadBuffer(url);
}
else if(ResourceType.IMAGE.test(url)) {
this.loadImage(url);
} // 其他資源類型處理...
});
}
loadBuffer(url) {
ht.Default.xhrLoad(url, res => {
this.onResourceLoaded(url, res);
}, {
responseType: 'arraybuffer'
});
}
// 其他加載方法...
onResourceLoaded(url, res) {
sourceMap[url] = res;
this.loaded++;
this.onProgress(this.loaded, this.resources.length);
if (this.loaded === this.resources.length) {
this.onAllLoaded();
}
}
// 加載進度回調
onProgress(loaded, total) {
console.log(`加載進度: ${loaded}/${total}`);
};
onAllLoaded() {
console.log("所有資源預加載完成");
// 進入主場景...
}
}
加載頁面優化
進度展示設計
class LoadingView{
constructor() {
this.initView();
}
initView(){
this.dm = new ht.DataModel();
this.view = new ht.graph.GraphView(this.dm);
let style = this.view.getView().style;
style.left = "0";
style.right = "0";
style.top = "0";
style.bottom = "0";
document.body.appendChild(this.view.getView());
}
// 更新進度
updateProgress(percent) {
}
// 移除加載頁面
remove() {
setTimeout(() => {
this.view.getView().remove();
this.enterMainScene();
}, 1);
}
// 進入主場景
enterMainScene(){
}
}
視覺優化建議
-
進度條設計:使用圖標實現平滑動畫。
-
背景動畫:添加輕量級背景動畫提升等待體驗。
- 分段進度:將加載過程分為資源加載、場景初始化等階段。
- 預估時間:基於已加載時間預測剩餘時間。
性能優化方案
Service Worker 離線緩存
// sw.js
let CACHE_NAME = 'ht-resources-v1';
self.addEventListener('fetch', event => {
event.respondWith(caches.match(event.request).then(function (response) {
if (response !== undefined) {
return response;
} else {
return fetch(event.request).then(function (response) {
if (event.request.url.indexOf('storage') != -1) {
let responseClone = response.clone();
caches.open(CACHE_NAME).then(function (cache) {
cache.put(event.request, responseClone);
});
}
return response;
}).catch(function () {
return caches.match('./');
});
}
}));
});
self.addEventListener('activate', function (event) {
event.waitUntil(clients.claim());
event.waitUntil(
caches.keys().then(function (keyList) {
returnPromise.all(keyList.map(function (key) {
if (key !== CACHE_NAME) {
// 刪除舊緩存
return caches.delete(key);
}
}));
})
);
});
資源壓縮策略
- 模型優化:輕量化模型,對模型進行減面。
- 圖片優化:圖片資源壓縮。
效果對比與總結
加載效果對比
預加載方案雖然初始顯示時間較長,但提供了更優的整體用户體驗:
- 完整的場景一次性呈現,避免零碎加載造成的視覺割裂。
- 無卡頓的交互體驗,所有資源已就緒。
- 可控的等待預期,進度反饋降低用户焦慮。
- 更穩定的性能表現,避免運行時資源加載導致的卡頓。
預加載效果如下
常規加載效果
適用場景
-
大型 3D 場景:包含複雜模型和紋理的場景。
- 儀表盤應用:需要快速響應的監控系統。
- 移動端應用:網絡條件不穩定的環境。
- 演示系統:需要流暢演示效果的場合。
實施建議
- 分階段實施:先對關鍵資源預加載,再逐步擴展。
- 性能監控:添加加載時間統計和分析。
- A/B 測試:對比不同策略的實際效果。
總結
綜上所述,本預加載方案能顯著提升 HT for Web 應用的加載性能和用户體驗,特別適合對流暢性要求高的可視化應用場景。在實際項目中,應根據資源規模和用户場景靈活調整預加載策略,平衡加載時間和用户體驗。