背景:egret重度游戏项目,ui资源都比较大,加载较慢,翻翻加载ui的源码看一下有没有优化空间:
https://github.com/fairygui/FairyGUI-egret/blob/master/source/src/UIPackage.ts
public static async loadPackage(resKey: string): Promise<UIPackage> {
return new Promise<UIPackage>(async resolve => {
let pkg: UIPackage = UIPackage._instById[resKey];
if (pkg) {
resolve(pkg);
return;
}
const asset = await RES.getResAsync(getAssetResKey(resKey, "fui"));
pkg = new UIPackage();
pkg._resKey = resKey;
pkg.loadPackage(new ByteBuffer(asset));
let cnt: number = pkg._items.length;
let tasks = [];
for (var i: number = 0; i < cnt; i++) {
var pi: PackageItem = pkg._items[i];
if (pi.type == PackageItemType.Atlas || pi.type == PackageItemType.Sound) {
tasks.push(RES.getResAsync(pi.file));
}
}
if (tasks.length > 0)
await Promise.all(tasks);
UIPackage._instById[pkg.id] = pkg;
UIPackage._instByName[pkg.name] = pkg;
UIPackage._instById[pkg._resKey] = pkg;
resolve(pkg);
});
}
可以看到代码里是先加载 .fui 的配置资源,等到它加载完成后,从其中解析出需要的 atlas\sound 资源,然后等待所有的资源加载,ui加载完成。而egret在运行会通过 assetsManager 加载全量资源的映射表,我们可以在此时建 收集每个fgui包的全部资源(即 .fgui配置 和 atlas\sound 资源),这样在loadPackage 时直接并行加载单个ui包的全部资源,理论上单个包的加载速度可以提升近一倍。
具体代码修改如下:
注意:代码是基于我这边内部版本修改,行数可能对不上,具体修改要参考一下上下文的scope。
修改后执行 ./tools/bin/egret build
编译js。
egret - assetsmanager:
src/extension/assetsmanager/src/core/FileSystem.ts
export interface FileSystem {
...
+++++++++++++++++++++>>>>>> line 44
collectFguiPkgAtlasAndSound(pkg:string, name:string):void;
getFguiPkgAtlasAndSounds(pkg:string): string[];
<<<<<<+++++++++++++++++++++
}
src/extension/assetsmanager/src/core/ResourceConfig.ts
export class ResourceConfig {
...
+++++++++++++++++++++>>>>>> line 265
public getFguiPkgItems(pkgName:string): string[] {
return config.config.fileSystem.getFguiPkgAtlasAndSounds(pkgName);
}
<<<<<<+++++++++++++++++++++
...
}
src/extension/assetsmanager/src/processor/Processor.ts
if (!fileSystem) {
fileSystem = {
...
+++++++++++++++++++++>>>>>> line 639
},
fguiPkgAtlasAndSound: {},
collectFguiPkgAtlasAndSound:(pkgName:string, name:string)=>{
let temp:string[] = fguiPkgAtlasAndSound[pkgName];
if (!temp) {
temp = [];
fguiPkgAtlasAndSound[pkgName] = temp;
}
temp.push(name);
},
getFguiPkgAtlasAndSounds:(pkgName:string)=>{
return fguiPkgAtlasAndSound[pkgName];
<<<<<<+++++++++++++++++++++
...
}
+++++++++++++++++++++>>>>>> line 667
let fguiPkgAtlasAndSound: {[index:string]:string[]} = fileSystem['fguiPkgAtlasAndSound'];
<<<<<<+++++++++++++++++++++
for (let resource of data.resources) {
...
+++++++++++++++++++++>>>>>> line 678
//fgui 资源
if (resource.url.substring(0,10) == "assets/ui/") {
let subfix = resource.url.substring(10+resource.name.length)
switch(subfix) {
case ".fui":
fileSystem.collectFguiPkgAtlasAndSound(resource.name, resource.name);
break;
case ".mp3":
let idx_ = resource.name.lastIndexOf('_');
fileSystem.collectFguiPkgAtlasAndSound(resource.name.substring(0,idx_), resource.name);
break
case ".jpg":
case ".png":
let idx_atlas = resource.name.lastIndexOf('_atlas');
fileSystem.collectFguiPkgAtlasAndSound(resource.name.substring(0,idx_atlas), resource.name);
break;
default:
console.warn("unparsered fgui resource :" + resource.url);
}
}
<<<<<<+++++++++++++++++++++
}
+++++++++++++++++++++>>>>>> line 702
for(let key in fguiPkgAtlasAndSound) {
let temp:string[] = fguiPkgAtlasAndSound[key];
temp.sort(); //排序后第一个应为 .fui文件
}
<<<<<<+++++++++++++++++++++
src/extension/assetsmanager/src/shim/Resource.ts
module RES {
...
+++++++++++++++++++++>>>>>> line 320
export function getFguiPkgItems(pkgName: string): string[] {
return instance.getFguiPkgItems(pkgName);
}
<<<<<<+++++++++++++++++++++
...
export class ResourceConfig {
...
+++++++++++++++++++++>>>>>> line 829
/**
* 获取配置文件中 fugi 包的资源名合集
* @method RES.getFguiPkgItems
* @param pkgName {string} 包名
* @returns {string[]}
*/
@checkNull
public getFguiPkgItems(pkgName:string): string[] {
return config.getFguiPkgItems(pkgName);
}
<<<<<<+++++++++++++++++++++
...
}
FairyGUI
src/UIPackage.ts
public static async loadPackage(resKey: string): Promise<UIPackage> {
...
let keys = RES.getFguiPkgItems(resKey);
for(let key of keys) {
tasks.push(RES.getResAsync(key))
}
let assets = await Promise.all(tasks);
pkg = new UIPackage();
pkg._resKey = resKey;
pkg.loadPackage(new ByteBuffer(assets[0]));
...
}