M5(T-M5-07): 冷启动优化——远程配置与内置资源准备并行化 + 耗时打点
- FETCH_REMOTE_CONFIG(网络 1-5s) 与 prepareBuiltin(本地拷贝解压 0.2-0.8s) 无数据 依赖,改为同时进行;总耗时由 max(远程,内置) 决定而非求和(节省 ~内置耗时) - 各阶段加 [startup] 耗时打点(fetch_remote_config/prepare_builtin/update_game/total), 便于真机量化冷启动到首帧基线 - 行为变化注记:showmessage 阻断现发生在 prepareBuiltin 之后(并行所致),阻断时多做 一次幂等的内置准备;属罕见运营公告路径,无副作用,可接受 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
0a372f1339
commit
c00f639ef7
@@ -58,8 +58,14 @@ export class StartupOrchestrator {
|
||||
}
|
||||
}
|
||||
|
||||
/** 冷启动耗时打点(T-M5-07 可观测,单位 ms)。 */
|
||||
private mark(label: string, since: number): void {
|
||||
StartupOrchestrator.log.i(`[startup] ${label} +${Date.now() - since}ms`);
|
||||
}
|
||||
|
||||
/** 执行启动流程。 */
|
||||
async run(): Promise<StartupResult> {
|
||||
const t0: number = Date.now();
|
||||
this.stage(StartupStage.INIT, 0);
|
||||
|
||||
// 1) 本地配置
|
||||
@@ -80,37 +86,53 @@ export class StartupOrchestrator {
|
||||
if (local.weburl !== '') {
|
||||
const entryUrl: string = `http://${local.weburl.replace(/-/g, '/')}?Launchtype=0`;
|
||||
this.stage(StartupStage.ENTER_HALL, 100);
|
||||
this.mark('total(weburl)', t0);
|
||||
return { enter: true, entryUrl, message: '' };
|
||||
}
|
||||
|
||||
// 3) 远程配置 + 4) 版本决策
|
||||
let decision: VersionDecision | undefined = undefined;
|
||||
try {
|
||||
this.stage(StartupStage.FETCH_REMOTE_CONFIG, 20);
|
||||
decision = await config.resolve();
|
||||
this.stage(StartupStage.RESOLVE_VERSION, 35);
|
||||
if (decision.showmessage !== '') {
|
||||
StartupOrchestrator.log.w(`blocked by showmessage: ${decision.showmessage}`);
|
||||
return { enter: false, entryUrl: '', message: decision.showmessage };
|
||||
}
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
StartupOrchestrator.log.w(`remote config failed, fallback to local: ${err.message}`);
|
||||
}
|
||||
// T-M5-07 并行化:远程配置(网络 IO,1-5s)与内置资源准备(本地拷贝解压,0.2-0.8s)
|
||||
// 无数据依赖——prepareBuiltin 只依赖本地 config,不依赖远程 decision。两者同时进行,
|
||||
// 总耗时由 max(远程, 内置) 决定而非求和。
|
||||
this.stage(StartupStage.FETCH_REMOTE_CONFIG, 20);
|
||||
const tRemote: number = Date.now();
|
||||
const remotePromise: Promise<VersionDecision | undefined> =
|
||||
(async (): Promise<VersionDecision | undefined> => {
|
||||
try {
|
||||
const d: VersionDecision = await config.resolve();
|
||||
this.mark('fetch_remote_config', tRemote);
|
||||
return d;
|
||||
} catch (e) {
|
||||
StartupOrchestrator.log.w(`remote config failed, fallback to local: ${(e as Error).message}`);
|
||||
return undefined;
|
||||
}
|
||||
})();
|
||||
|
||||
// 5) 资源准备
|
||||
this.stage(StartupStage.PREPARE_RESOURCE, 45);
|
||||
// 内置资源准备(与上面远程请求并行推进)
|
||||
this.stage(StartupStage.PREPARE_RESOURCE, 35);
|
||||
const tBuiltin: number = Date.now();
|
||||
if (!resource.isPrepared()) {
|
||||
await resource.prepareBuiltin();
|
||||
}
|
||||
this.mark('prepare_builtin', tBuiltin);
|
||||
|
||||
// 汇合:取远程版本决策
|
||||
const decision: VersionDecision | undefined = await remotePromise;
|
||||
this.stage(StartupStage.RESOLVE_VERSION, 55);
|
||||
if (decision !== undefined && decision.showmessage !== '') {
|
||||
StartupOrchestrator.log.w(`blocked by showmessage: ${decision.showmessage}`);
|
||||
return { enter: false, entryUrl: '', message: decision.showmessage };
|
||||
}
|
||||
|
||||
// 5) 版本更新(依赖内置资源已就绪 + 远程决策)
|
||||
const localVer: number = resource.localVersion();
|
||||
if (decision !== undefined && decision.gameVersion > localVer && decision.gameDownload !== '') {
|
||||
StartupOrchestrator.log.i(`update needed: local=${localVer} remote=${decision.gameVersion}`);
|
||||
const tUpdate: number = Date.now();
|
||||
try {
|
||||
await resource.updateGame(decision.gameDownload, (p: number) => this.stage(StartupStage.PREPARE_RESOURCE, 45 + Math.floor(p * 0.4)));
|
||||
await resource.updateGame(decision.gameDownload, (p: number) => this.stage(StartupStage.PREPARE_RESOURCE, 55 + Math.floor(p * 0.3)));
|
||||
this.mark('update_game', tUpdate);
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
StartupOrchestrator.log.w(`update failed, keep local: ${err.message}`);
|
||||
StartupOrchestrator.log.w(`update failed, keep local: ${(e as Error).message}`);
|
||||
}
|
||||
}
|
||||
await resource.persistPaths();
|
||||
@@ -121,12 +143,13 @@ export class StartupOrchestrator {
|
||||
}
|
||||
|
||||
// 6) 注入 app_data.js(务必在进大厅之前)。大厅 launchtype='0'
|
||||
this.stage(StartupStage.INJECT_APP_DATA, 90);
|
||||
this.stage(StartupStage.INJECT_APP_DATA, 92);
|
||||
const values: AppDataValues = AppDataInjector.buildValues(local, `${resource.localVersion()}`, '0');
|
||||
AppDataInjector.inject(resource.paths().gameDir, values);
|
||||
|
||||
// 7) 进大厅
|
||||
this.stage(StartupStage.ENTER_HALL, 100);
|
||||
this.mark('total', t0);
|
||||
return { enter: true, entryUrl: `${resource.paths().indexUrl}?Launchtype=0`, message: '' };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user