如何更高效地在HTML中加载资源:基于JavaScript的HTML游戏Zip资源非单行加载优化
高效加载Zip资源的替代方案
你当前把整个Zip资源编码成base85塞进<script type="p4-project">的方式,确实会带来代码臃肿、加载解码开销大的问题。下面给你几个更合理的优化方案,从最优到过渡方案排序:
方案1:直接加载独立的Zip资源文件(推荐)
把游戏资源Zip作为单独的静态文件(比如game-assets.zip)放在服务器上,用fetch直接请求它,完全抛弃base85编码和script标签的方式。浏览器可以直接缓存Zip文件,加载速度更快,代码结构也更整洁。
修改你的getProjectData函数如下:
const getProjectData = (function() { const storage = scaffolding.storage; storage.onprogress = (total, loaded) => { setProgress(interpolate(0.75, 0.98, loaded / total)); }; storage.addHelper({ load: (assetType, assetId, dataFormat) => zip.file(assetId + '.' + dataFormat) .async('uint8array') .then((data) => new storage.Asset(assetType, assetId, dataFormat, data)) }); return () => (async () => { // 替换成你的Zip资源实际URL const response = await fetch('game-assets.zip'); const zipData = await response.arrayBuffer(); zip = await Scaffolding.JSZip.loadAsync(zipData); return zip.file('project.json').async('arraybuffer'); })(); })();
核心优势:
- 消除base85编码/解码的额外性能开销
- Zip文件可被浏览器缓存,重复访问加载更快
- 主HTML不再被大量编码内容塞满,代码结构清晰
- 能利用浏览器并行加载能力提升速度
方案2:资源清单+按需加载
如果游戏资源量很大,不需要一次性加载全部,可以先加载轻量的资源清单(比如asset-manifest.json),再根据游戏进度按需加载单个资源(可拆分多个小Zip或直接加载单个资源文件)。
示例实现步骤:
- 服务器放置
asset-manifest.json,列出所有资源的路径、类型、ID - 初始只加载清单,后续按需加载需要的资源
修改后的加载逻辑示例:
const getProjectData = async () => { // 先加载资源清单 const manifestResp = await fetch('asset-manifest.json'); const manifest = await manifestResp.json(); // 加载核心的project.json const projectResp = await fetch(manifest.projectJsonPath); const projectData = await projectResp.arrayBuffer(); // 配置storage为按需加载单个资源 const storage = scaffolding.storage; storage.onprogress = (total, loaded) => { setProgress(interpolate(0.75, 0.98, loaded / total)); }; storage.addHelper({ load: async (assetType, assetId, dataFormat) => { const asset = manifest.assets.find(a => a.id === assetId && a.format === dataFormat); if (!asset) throw new Error(`Asset ${assetId}.${dataFormat} not found`); const resp = await fetch(asset.path); const data = await resp.arrayBuffer(); return new storage.Asset(assetType, assetId, dataFormat, new Uint8Array(data)); } }); return projectData; };
核心优势:
- 初始加载量极小,游戏启动速度更快
- 避免加载当前不需要的资源,节省带宽和内存
- 资源更新更灵活,无需重新打包整个Zip
方案3:过渡方案——将base85内容移到单独文件
如果暂时无法彻底修改架构,可以把base85编码内容单独存成文本文件(比如project-data.b85),用fetch加载它,至少能解决主HTML代码堆叠混乱的问题。
修改后的getProjectData函数:
const getProjectData = (function() { const storage = scaffolding.storage; storage.onprogress = (total, loaded) => { setProgress(interpolate(0.75, 0.98, loaded / total)); }; storage.addHelper({ load: (assetType, assetId, dataFormat) => zip.file(assetId + '.' + dataFormat) .async('uint8array') .then((data) => new storage.Asset(assetType, assetId, dataFormat, data)) }); // 保留原base85解码逻辑 const base85decode = e=>{const t=e=>(40===e&&(e=60),41===e&&(e=62),e-42),n=e.indexOf(","),c=+e.substring(0,n),o=new ArrayBuffer((s=c)%4==0?s:s+(4-s%4));var s;const a=new Uint32Array(o);for(let c=n+1,o=0;c<e.length;c+=5,o++)a[o]=85*t(e.charCodeAt(c+4))*85*85*85+85*t(e.charCodeAt(c+3))*85*85+85*t(e.charCodeAt(c+2))*85+85*t(e.charCodeAt(c+1))+t(e.charCodeAt(c));return new Uint8Array(o,0,c)}; return () => (async () => { // 加载单独的base85文件 const response = await fetch('project-data.b85'); const base85Content = await response.text(); const result = base85decode(base85Content); zip = await Scaffolding.JSZip.loadAsync(result); return zip.file('project.json').async('arraybuffer'); })(); })();
核心优势:
- 无需大幅修改现有解码逻辑
- 主HTML恢复整洁,不再被大量编码内容占用
- 单独的base85文件可被缓存,提升重复加载速度
内容的提问来源于stack exchange,提问作者Aurion games
相关产品推荐
相关产品推荐

