加载优化
阅读时间:3分钟更新于 2025-05-29 11:50
耗时统计

加载耗时
执行 assetManager.loadScene
时会在控制台打印每个阶段的耗时情况,如:
[Galacean Effects] Load asset: totalTime: 270.8000ms [loadJSON: 74.80] [processJSON: 0.40] [processFontURL: 1.30] [plugin:processAssets: 2.00] [processBins: 73.80] [processImages: 194.00] [processTextures: 0.30] [plugin:prepareResource: 0.10], url: https://xxx.
具体含义如下:
- totalTime: 加载总耗时
- loadJSON: 加载
.json
的网络耗时 - processJSON: 对 JSON 数据进行预处理
- processBins: 加载
.bin
文件并进行预处理 - processImages: 加载图片(含动态换图/视频、压缩纹理)文件并进行预处理
- processFontURL: 加载
.ttf
的字体文件并进行预处理 - plugin:processAssets: 插件生命周期的
processAssets
,插件加载所需类型资源(如:音/视频资源) - processTextures: 图片相关资源转
Texture options
- plugin:prepareResource: 插件生命周期的
prepareResource
,插件对加载好的资源做进一步处理
首帧耗时
首帧耗时是指从加载到第一帧渲染的时间,也就是用户看到画面的耗时。
首帧耗时主要经过两个阶段:
- 相关资源的网络请求及初处理(即:加载耗时)。
- GPU 编译等,所有的 WebGL 程序在绘制之前都需要编译 Shader(编译耗时优化由 player 处理)。
Player 会在日志里记录第一帧耗时,当然你也可以自己测试:
interface CompositionStatistic {
loadTime: number, // 资源加载时间
compileTime: number, // Shader 编译耗时
firstFrameTime: number, // 首帧耗时
}
player
.loadScene('xx.json') // 资源加载
.then(composition => {
console.log(composition.statistic);
});
// 打印结果如:
loadTime: 1062.1000000238419
compileTime: 18.5
firstFrameTime: 1250.699999988079
执行 player.loadScene
时会在控制台打印每个阶段的耗时情况,如:
[Galacean Effects] Shader async compile [新建合成3]: 9.6000ms.
[Galacean Effects] First frame [新建合成3]: 28.4000ms.
综上所述,加载耗时一般由网络状况决定,首帧耗时除了加载和编译耗时,还会有一些资源处理耗时(如上图中的实例化合成/元素/GPU 纹理等)。
编译耗时与动效复杂性和设备性能有关,动效越复杂,所需要编译的 Shader 就越复杂,设备处理耗时越高。
为避免复杂动效在播放时的卡顿或延迟,可以对资源进行预加载并提前做编译。
资源预加载
如上所示,一个动画的播放由资源载入和播放动画两部分组成,这两部分的耗时是没办法避免的。但是如果我们想继续优化动画播放的体验,这就需要我们将资源载入部分和播放动画拆分,提前将资源准备好,在播放的时候只需要播放动画就可以了,代码参考如下:
/*** === 资源准备阶段 === ***/
// 创建一个资源加载器
const assetManager = new AssetManager();
// 进行资源的加载
const scene = await assetManager.loadScene('xxx.json');
// 其他业务逻辑代码
/*** === 资源准备阶段 === ***/
/*** === 预编译准备阶段 === ***/
// 加载动画资源
await player.loadScene(scene, { autoplay: false });
/*** === 预编译准备阶段 === ***/
// 手动播放
player.play();
为保证渲染前所有所需资源都准备好,所以动态替换的图片也需要预加载,即:如果有动态换图(含动态视频),需要在初始化 AssetManager
时配置:
const assetManager = new AssetManager({
variables: {
image: 'https://xxx',
},
});
await player.loadScene(scene, {
variables: {
text_3: 'Dynamic Text',
},
});
注意:
- 预加载仅对资源生效,所以,文本或富文本元素的动态替换在
AssetManager
预加载中不会生效,请在player.loadScene
中替换。 - 在资源准备阶段,可以不用准备 Canvas 画布,但是到了预编译准备阶段,就需要准备好 Canvas 画布,因为 shader 预编译需要 gl 对象。
- 当我们需要在不同的 player 中播放时,请创建多个
AssetManager
对象进行资源加载,保证Player
对象和AssetManager
对象一一对应。
超时设置
有些场景对动画的出现时间要求很高,在没法做预加载的情况下,我们需要保证业务流程的顺畅,可以控制动画加载超时,如:1 秒加载完成并播放出来,如果此时间未能完成,可以及时用降级图兜底。
loadScene
支撑直接设置 timeout
,默认是 10 秒:
const player = new Player({
container,
onError: err => {
player.dispose();
player = null;
// 超时的兜底处理
console.error(err);
},
});
// 700ms 内未完成加载会抛出超时错误
await player.loadScene(json, { timeout: 0.7 });
注意:
- 非特殊情况,请不要自己加超时,可能会引起各种奇怪的报错,如下强烈不推荐:
// ❌ 不推荐
setTimeout(() => {
player?.dispose();
player = null;
throw new Error('timeout');
}, 700);
Preview