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> {
|
async run(): Promise<StartupResult> {
|
||||||
|
const t0: number = Date.now();
|
||||||
this.stage(StartupStage.INIT, 0);
|
this.stage(StartupStage.INIT, 0);
|
||||||
|
|
||||||
// 1) 本地配置
|
// 1) 本地配置
|
||||||
@@ -80,37 +86,53 @@ export class StartupOrchestrator {
|
|||||||
if (local.weburl !== '') {
|
if (local.weburl !== '') {
|
||||||
const entryUrl: string = `http://${local.weburl.replace(/-/g, '/')}?Launchtype=0`;
|
const entryUrl: string = `http://${local.weburl.replace(/-/g, '/')}?Launchtype=0`;
|
||||||
this.stage(StartupStage.ENTER_HALL, 100);
|
this.stage(StartupStage.ENTER_HALL, 100);
|
||||||
|
this.mark('total(weburl)', t0);
|
||||||
return { enter: true, entryUrl, message: '' };
|
return { enter: true, entryUrl, message: '' };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) 远程配置 + 4) 版本决策
|
// T-M5-07 并行化:远程配置(网络 IO,1-5s)与内置资源准备(本地拷贝解压,0.2-0.8s)
|
||||||
let decision: VersionDecision | undefined = undefined;
|
// 无数据依赖——prepareBuiltin 只依赖本地 config,不依赖远程 decision。两者同时进行,
|
||||||
try {
|
// 总耗时由 max(远程, 内置) 决定而非求和。
|
||||||
this.stage(StartupStage.FETCH_REMOTE_CONFIG, 20);
|
this.stage(StartupStage.FETCH_REMOTE_CONFIG, 20);
|
||||||
decision = await config.resolve();
|
const tRemote: number = Date.now();
|
||||||
this.stage(StartupStage.RESOLVE_VERSION, 35);
|
const remotePromise: Promise<VersionDecision | undefined> =
|
||||||
if (decision.showmessage !== '') {
|
(async (): Promise<VersionDecision | undefined> => {
|
||||||
StartupOrchestrator.log.w(`blocked by showmessage: ${decision.showmessage}`);
|
try {
|
||||||
return { enter: false, entryUrl: '', message: decision.showmessage };
|
const d: VersionDecision = await config.resolve();
|
||||||
}
|
this.mark('fetch_remote_config', tRemote);
|
||||||
|
return d;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const err = e as Error;
|
StartupOrchestrator.log.w(`remote config failed, fallback to local: ${(e as Error).message}`);
|
||||||
StartupOrchestrator.log.w(`remote config failed, fallback to local: ${err.message}`);
|
return undefined;
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// 5) 资源准备
|
// 内置资源准备(与上面远程请求并行推进)
|
||||||
this.stage(StartupStage.PREPARE_RESOURCE, 45);
|
this.stage(StartupStage.PREPARE_RESOURCE, 35);
|
||||||
|
const tBuiltin: number = Date.now();
|
||||||
if (!resource.isPrepared()) {
|
if (!resource.isPrepared()) {
|
||||||
await resource.prepareBuiltin();
|
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();
|
const localVer: number = resource.localVersion();
|
||||||
if (decision !== undefined && decision.gameVersion > localVer && decision.gameDownload !== '') {
|
if (decision !== undefined && decision.gameVersion > localVer && decision.gameDownload !== '') {
|
||||||
StartupOrchestrator.log.i(`update needed: local=${localVer} remote=${decision.gameVersion}`);
|
StartupOrchestrator.log.i(`update needed: local=${localVer} remote=${decision.gameVersion}`);
|
||||||
|
const tUpdate: number = Date.now();
|
||||||
try {
|
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) {
|
} catch (e) {
|
||||||
const err = e as Error;
|
StartupOrchestrator.log.w(`update failed, keep local: ${(e as Error).message}`);
|
||||||
StartupOrchestrator.log.w(`update failed, keep local: ${err.message}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await resource.persistPaths();
|
await resource.persistPaths();
|
||||||
@@ -121,12 +143,13 @@ export class StartupOrchestrator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 6) 注入 app_data.js(务必在进大厅之前)。大厅 launchtype='0'
|
// 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');
|
const values: AppDataValues = AppDataInjector.buildValues(local, `${resource.localVersion()}`, '0');
|
||||||
AppDataInjector.inject(resource.paths().gameDir, values);
|
AppDataInjector.inject(resource.paths().gameDir, values);
|
||||||
|
|
||||||
// 7) 进大厅
|
// 7) 进大厅
|
||||||
this.stage(StartupStage.ENTER_HALL, 100);
|
this.stage(StartupStage.ENTER_HALL, 100);
|
||||||
|
this.mark('total', t0);
|
||||||
return { enter: true, entryUrl: `${resource.paths().indexUrl}?Launchtype=0`, message: '' };
|
return { enter: true, entryUrl: `${resource.paths().indexUrl}?Launchtype=0`, message: '' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user