@ives_xxz/framework 1.4.12 → 1.4.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/FW.d.ts CHANGED
@@ -35,6 +35,7 @@ declare namespace FW {
35
35
  taskMgr: TaskManager;
36
36
  hotUpdateMgr: HotUpdateManager;
37
37
  promiseMgr: PromiseManager;
38
+ performanceMgr: PerformanceManager;
38
39
  scene: Scene;
39
40
  bundleName: string;
40
41
  getComponent<T>(serviceIdentifier: FW.ServiceIdentifier<T>): T;
@@ -49,6 +50,8 @@ declare namespace FW {
49
50
  onDestroy(): void;
50
51
  };
51
52
 
53
+ type Manager = {};
54
+
52
55
  type PromiseManager = {
53
56
  execute<T = any>(
54
57
  executor: (
@@ -1611,6 +1614,12 @@ declare namespace FW {
1611
1614
  setEffectsMute(mute: boolean): void;
1612
1615
  };
1613
1616
 
1617
+ type PerformanceManager = {
1618
+ recordOperationMetric(manager: string, operation: string, duration: number): void;
1619
+ getManagerReport(manager: string): PerformanceReport;
1620
+ getAllReports(): Map<string, FW.PerformanceReport>;
1621
+ };
1622
+
1614
1623
  type Object = {
1615
1624
  /** 是否已经初始化 */
1616
1625
  initialize: boolean;
@@ -1779,7 +1788,7 @@ declare namespace FW {
1779
1788
  */
1780
1789
  type TaskFunction = () => TaskGenerator;
1781
1790
 
1782
- type PerformanceReport = {
1791
+ type TaskPerformanceReport = {
1783
1792
  startTime: string;
1784
1793
  endTime: string;
1785
1794
  totalTasks: number;
@@ -1833,7 +1842,7 @@ declare namespace FW {
1833
1842
  /**
1834
1843
  * 获取任务性能报告
1835
1844
  */
1836
- getPerformanceReport(): PerformanceReport;
1845
+ getPerformanceReport(): TaskPerformanceReport;
1837
1846
  };
1838
1847
 
1839
1848
  type FrameDetail = {
@@ -1928,6 +1937,49 @@ declare namespace FW {
1928
1937
 
1929
1938
  type PromiseStatus = 'pending' | 'fulfilled' | 'rejected' | 'cancelled';
1930
1939
 
1940
+ /**
1941
+ * 性能管理器配置
1942
+ */
1943
+ type PerformanceManagerOptions = {
1944
+ /** 是否自动收集性能数据 */
1945
+ autoCollect?: boolean;
1946
+ /** 性能数据保留时间(毫秒) */
1947
+ dataRetentionTime?: number;
1948
+ /** 采样率(0-1) */
1949
+ samplingRate?: number;
1950
+ /** 性能警告阈值(毫秒) */
1951
+ warningThreshold?: number;
1952
+ };
1953
+
1954
+ /**
1955
+ * 性能统计报告
1956
+ */
1957
+ type PerformanceReport = {
1958
+ manager: string;
1959
+ totalOperations: number;
1960
+ averageDuration: number;
1961
+ minDuration: number;
1962
+ maxDuration: number;
1963
+ recentMetrics: FWPerformanceMetric[];
1964
+ };
1965
+
1966
+ /**
1967
+ * 性能指标数据
1968
+ */
1969
+ type PerformanceMetric = {
1970
+ manager: string;
1971
+ operation: string;
1972
+ duration: number;
1973
+ timestamp: number;
1974
+ };
1975
+
1976
+ type ManagerOptions = {
1977
+ /** 是否启用调试日志 */
1978
+ debug?: boolean;
1979
+ /** 管理器名称(默认使用类名) */
1980
+ name?: string;
1981
+ };
1982
+
1931
1983
  declare function timeScale(scale: number);
1932
1984
  declare let Entry: Entry;
1933
1985
  }
package/entry/FWEntry.ts CHANGED
@@ -19,6 +19,7 @@ import FWTaskManager from '../manager/FWTaskManager';
19
19
  import FWEngineManager from '../manager/FWEngineManager';
20
20
  import FWHotUpdateManager from '../manager/FWHotUpdateManager';
21
21
  import FWPromiseManager from '../manager/FWPromiseManager';
22
+ import { FWPerformanceManager } from '../manager/FWPerformanceManager';
22
23
 
23
24
  /**
24
25
  * 入口脚本
@@ -89,6 +90,10 @@ export default class FWEntry implements FW.Entry {
89
90
  * promise管理器
90
91
  */
91
92
  promiseMgr: FW.PromiseManager;
93
+ /**
94
+ * 性能管理器
95
+ */
96
+ performanceMgr: FW.PerformanceManager;
92
97
  /**
93
98
  * 当前Scene
94
99
  */
@@ -119,7 +124,7 @@ export default class FWEntry implements FW.Entry {
119
124
  this.languageMgr = new FWLanguageManager();
120
125
  this.hotUpdateMgr = new FWHotUpdateManager();
121
126
  this.promiseMgr = new FWPromiseManager();
122
-
127
+ this.performanceMgr = new FWPerformanceManager();
123
128
  this.resMgr.initialize();
124
129
  this.layerMgr.initialize();
125
130
  this.timeMgr.initialize();
@@ -131,43 +131,46 @@ export class FWAssetManager extends FWManager implements FW.AssetManager {
131
131
 
132
132
  assetData.loaded = false;
133
133
 
134
- return FW.Entry.promiseMgr.execute(
135
- (resolve, reject, signal) => {
136
- const self = this;
137
- bundle.load(
138
- path,
139
- type,
140
- (finish: number, total: number, item: cc.AssetManager.RequestItem) => {
141
- progress?.(finish, total, item);
142
- },
143
- (err: Error, asset: cc.Asset) => {
144
- if (err || !asset) {
145
- reject(err);
146
- return;
147
- }
148
-
149
- assetData.loaded = true;
150
- assetData.dependentBundle = bundleName;
151
- assetData.uuid = asset['_uuid'];
152
- assetData.autoRelease = autoRelease;
153
- assetData.asset = asset;
154
- assetData.user = assetProperty.user;
155
- assetData.refCount = 1;
156
- assetData.assetProperty = assetProperty;
157
-
158
- self.assetsMap.set(key, assetData);
159
-
160
- cb?.(assetData);
161
- resolve(assetData);
162
- },
163
- );
164
- },
165
- {
166
- retryCount: 3,
167
- retryInterval: 1,
168
- timeout: 10,
169
- },
170
- ).promise;
134
+ return await this.invoke(
135
+ FW.Entry.promiseMgr.execute(
136
+ (resolve, reject, signal) => {
137
+ const self = this;
138
+
139
+ bundle.load(
140
+ path,
141
+ type,
142
+ (finish: number, total: number, item: cc.AssetManager.RequestItem) => {
143
+ progress?.(finish, total, item);
144
+ },
145
+ (err: Error, asset: cc.Asset) => {
146
+ if (err || !asset) {
147
+ reject(err);
148
+ return;
149
+ }
150
+ assetData.loaded = true;
151
+ assetData.dependentBundle = bundleName;
152
+ assetData.uuid = asset['_uuid'];
153
+ assetData.autoRelease = autoRelease;
154
+ assetData.asset = asset;
155
+ assetData.user = assetProperty.user;
156
+ assetData.refCount = 1;
157
+ assetData.assetProperty = assetProperty;
158
+
159
+ self.assetsMap.set(key, assetData);
160
+
161
+ cb?.(assetData);
162
+ resolve(assetData);
163
+ },
164
+ );
165
+ },
166
+ {
167
+ retryCount: 3,
168
+ retryInterval: 1,
169
+ timeout: 10,
170
+ },
171
+ ).promise,
172
+ `loadAssets -> ${assetProperty.path}`,
173
+ );
171
174
  }
172
175
  /**
173
176
  * 加载文件夹
@@ -3,7 +3,8 @@ import FWLog from '../log/FWLog';
3
3
  import { FWManager } from './FWManager';
4
4
 
5
5
  export default class FWEngineManager extends FWManager implements FW.EngineManager {
6
- debug: boolean = CC_DEBUG;
6
+ debug: boolean = false;
7
+
7
8
  initialize() {
8
9
  this.registerCCCSystemEvent();
9
10
  }
@@ -7,6 +7,218 @@ import { FWQueue } from '../utils/FWQueue';
7
7
 
8
8
  const ADD_EXTERNAL_REFERENCE: string = 'addExternalReference';
9
9
 
10
+ export class FWLayerManager extends FWManager implements FW.LayerManager {
11
+ private resourceManager: FWLayerResourceManager;
12
+ private dataManager: FWLayerDataManager;
13
+ private createManager: FWLayerCreateManager;
14
+ private stackManager: FWLayerStackManager;
15
+ private stateManager: FWLayerStateManager;
16
+ private queueManager: FWLayerQueueManager;
17
+ private openManager: FWLayerOpenManager;
18
+
19
+ public initialize(): void {
20
+ this.resourceManager = new FWLayerResourceManager();
21
+ this.dataManager = new FWLayerDataManager();
22
+ this.createManager = new FWLayerCreateManager();
23
+ this.stackManager = new FWLayerStackManager();
24
+ this.stateManager = new FWLayerStateManager();
25
+ this.queueManager = new FWLayerQueueManager();
26
+
27
+ this.openManager = new FWLayerOpenManager(
28
+ this.dataManager,
29
+ this.resourceManager,
30
+ this.createManager,
31
+ this.stackManager,
32
+ this.queueManager,
33
+ );
34
+ }
35
+
36
+ /**
37
+ * 异步打开Layer
38
+ */
39
+ async openAsync<Ctr extends FW.LayerController = FW.LayerController>(
40
+ data: FW.LayerOpenArgs,
41
+ ): Promise<Ctr> {
42
+ return this.openManager.openLayerAsync(data) as Promise<Ctr>;
43
+ }
44
+
45
+ /**
46
+ * 同步打开
47
+ */
48
+ openSync<Ctr extends FW.LayerController = FW.LayerController>(data: FW.LayerOpenArgs): Ctr {
49
+ return this.openManager.openLayerSync(data) as unknown as Ctr;
50
+ }
51
+
52
+ /**
53
+ * 显示layer并恢复所有节点事件
54
+ */
55
+ displayLayer<Ctr extends FW.LayerController = FW.LayerController>(ctr: Ctr): Ctr {
56
+ const layerData = ctr.layerData;
57
+
58
+ if (!this.dataManager.getLayerMap().has(ctr.layerData.controllerConstructor)) {
59
+ FWLog.warn(`display layer failed,layer name : ${layerData.layerName}`);
60
+ return;
61
+ }
62
+ /** 非常驻layer不允许操作透明度显示 */
63
+ if (ctr.layerType != FWSystemDefine.FWLayerType.PERMANENT) return;
64
+
65
+ const node = ctr.layer.node;
66
+ node.opacity = 255;
67
+ node.resumeSystemEvents(true);
68
+
69
+ FW.Entry.evtMgr.targetResume(ctr);
70
+ FW.Entry.timeMgr.resumeSchedule(ctr);
71
+
72
+ return ctr;
73
+ }
74
+
75
+ /**
76
+ * 隐藏layer并隐藏所有节点事件
77
+ */
78
+ hideLayer<Ctr extends FW.LayerController = FW.LayerController>(ctr: Ctr): Ctr {
79
+ const layerData = ctr.layerData;
80
+ if (!this.dataManager.getLayerMap().has(ctr.layerData.controllerConstructor)) {
81
+ FWLog.warn(`hide layer failed,layer name : ${layerData.layerName}`);
82
+ return;
83
+ }
84
+
85
+ /** 非常驻layer不允许操作透明度 */
86
+ if (ctr.layerType != FWSystemDefine.FWLayerType.PERMANENT) return;
87
+
88
+ const node = ctr.layer.node;
89
+ node.opacity = 0;
90
+ node.pauseSystemEvents(true);
91
+ FW.Entry.evtMgr.targetPause(ctr);
92
+ FW.Entry.timeMgr.pauseSchedule(ctr);
93
+
94
+ return ctr;
95
+ }
96
+
97
+ /**
98
+ * 通过layer名字关闭
99
+ */
100
+ closeFromLayerName(name: string | string[]): void {
101
+ this.dataManager.getLayerMap().forEach((v) => {
102
+ if (Array.isArray(name)) {
103
+ name.forEach((n) => {
104
+ if (n === v.layerName) {
105
+ this.close(v.controller);
106
+ }
107
+ });
108
+ } else {
109
+ if (v.layerName == name) {
110
+ this.close(v.controller);
111
+ }
112
+ }
113
+ });
114
+ }
115
+
116
+ /**
117
+ * 从栈关闭
118
+ */
119
+ closeFromStack(count?: number) {
120
+ count = count ? count : 1;
121
+ for (let i = 0; i < count; i++) {
122
+ let layerData = this.stackManager.pop();
123
+ let ctr = layerData.controller;
124
+ if (!this.dataManager.getLayerMap().has(layerData.controllerConstructor)) {
125
+ return;
126
+ }
127
+ if (cc.isValid(ctr.layer?.node)) {
128
+ ctr.layer.destroy?.();
129
+ if (ctr.autoRelease) {
130
+ FW.Entry.resMgr.releaseAsset(ctr.layerData.layerAssetProperty);
131
+ }
132
+ this.dataManager.notifyExternalRefUpdates(ctr.layerData);
133
+ }
134
+ this.dataManager.removeFromMap(layerData.controllerConstructor);
135
+ }
136
+ }
137
+ /**
138
+ * 移除指定Layer所有子Layer
139
+ * @param layer
140
+ * @returns
141
+ */
142
+ async removeAllChildren(node: cc.Node) {
143
+ if (!cc.isValid(node)) return;
144
+ const layers = node.getComponentsInChildren(FWLayer);
145
+ layers.forEach((v) => {
146
+ if (cc.isValid(v?.node)) {
147
+ v?.ctr?.close();
148
+ }
149
+ });
150
+ }
151
+
152
+ /**
153
+ * 关闭layer
154
+ */
155
+ async close<Ctr extends FW.LayerController = FW.LayerController>(
156
+ ctr: Ctr,
157
+ ): Promise<FW.LayerController> {
158
+ if (!ctr) return;
159
+
160
+ let layerData = ctr.layerData;
161
+
162
+ if (cc.isValid(ctr.layer?.node)) {
163
+ await ctr.onClose?.();
164
+ ctr.destroy?.();
165
+ if (ctr.autoRelease) {
166
+ FW.Entry.resMgr.releaseAsset(ctr.layerData.layerAssetProperty);
167
+ }
168
+ this.dataManager.notifyExternalRefUpdates(ctr.layerData);
169
+ }
170
+
171
+ this.dataManager.removeFromMap(layerData.controllerConstructor);
172
+ this.dataManager.removeFromRegistry(ctr.layerData.controllerConstructor);
173
+
174
+ const index = this.stackManager.getStack().findIndex((v) => {
175
+ v.controller == ctr;
176
+ });
177
+ if (index > -1) {
178
+ this.stackManager.getStack().splice(index, 1);
179
+ }
180
+
181
+ /** 如果队列中还有等待打开的layer */
182
+ if (!this.queueManager.isEmpty()) {
183
+ const nextLayerData = this.queueManager.getNextLayer();
184
+ /** 先尝试同步打开 */
185
+ const nextLayer = this.openSync({
186
+ parent: nextLayerData.layerParent,
187
+ position: nextLayerData.layerPosition,
188
+ type: nextLayerData.controllerConstructor,
189
+ });
190
+ /** 如果同步打开失败,再次尝试异步打开(可能由于资源所在bundle并未提前加载) */
191
+ if (!nextLayer) {
192
+ return this.openAsync({
193
+ parent: nextLayerData.layerParent,
194
+ position: nextLayerData.layerPosition,
195
+ type: nextLayerData.controllerConstructor,
196
+ });
197
+ } else {
198
+ return nextLayer;
199
+ }
200
+ } else {
201
+ return undefined;
202
+ }
203
+ }
204
+
205
+ getLayerMap(): Map<new () => FW.LayerController, FWLayerData> {
206
+ return this.dataManager.getLayerMap();
207
+ }
208
+
209
+ public clear() {
210
+ this.queueManager.clear();
211
+ this.stackManager.clear();
212
+ this.stateManager.clear();
213
+ this.dataManager.clear();
214
+ this.dataManager.getLayerMap().forEach((v) => this.close(v.controller));
215
+ }
216
+
217
+ public onDestroy(): void {
218
+ this.clear();
219
+ }
220
+ }
221
+
10
222
  export class FWLayerData<T extends FW.LayerController = FW.LayerController>
11
223
  implements FW.LayerData
12
224
  {
@@ -240,41 +452,66 @@ class FWLayerOpenManager {
240
452
  /**
241
453
  * 统一的Layer打开方法
242
454
  */
243
- async openLayer<Ctr extends FW.LayerController = FW.LayerController>(
455
+ async openLayerAsync<Ctr extends FW.LayerController = FW.LayerController>(
244
456
  data: FW.LayerOpenArgs,
245
- isAsync: boolean,
246
457
  ): Promise<Ctr> {
247
458
  if (!this.validateOpenData(data)) {
248
- return this.getUndefinedResult(isAsync);
459
+ return undefined;
249
460
  }
250
461
 
251
462
  const existingLayer = this.dataManager.getExistingLayer(data.type);
252
463
  if (existingLayer) {
253
- return this.wrapResult(existingLayer, isAsync) as Ctr;
464
+ return existingLayer as Ctr;
254
465
  }
255
466
 
256
467
  const layerData = this.dataManager.createLayerData(data.type);
257
468
 
258
469
  if (!layerData) {
259
- return this.getUndefinedResult(isAsync);
470
+ return undefined;
260
471
  }
261
472
 
262
473
  if (this.dataManager.addRegistry(data.type)) {
263
474
  const proxy = this.dataManager.getExistingProxy(data.type);
264
- return this.wrapResult(proxy, isAsync) as Ctr;
475
+ return proxy as Ctr;
265
476
  }
266
477
 
267
478
  if (this.queueManager.handlePopupQueue(layerData, this.dataManager.getLayerMap())) {
268
- return this.getUndefinedResult(isAsync);
479
+ return undefined;
269
480
  }
270
481
 
271
482
  this.dataManager.addLayerData(data.type, layerData);
272
483
 
273
- if (isAsync) {
274
- return this.asyncGenerationLayer(layerData, data);
275
- } else {
276
- return this.syncGenerationLayer(layerData, data) as Ctr;
484
+ return this.asyncGenerationLayer(layerData, data);
485
+ }
486
+
487
+ openLayerSync<Ctr extends FW.LayerController = FW.LayerController>(data: FW.LayerOpenArgs): Ctr {
488
+ if (!this.validateOpenData(data)) {
489
+ return undefined;
277
490
  }
491
+
492
+ const existingLayer = this.dataManager.getExistingLayer(data.type);
493
+ if (existingLayer) {
494
+ return existingLayer as Ctr;
495
+ }
496
+
497
+ const layerData = this.dataManager.createLayerData(data.type);
498
+
499
+ if (!layerData) {
500
+ return undefined;
501
+ }
502
+
503
+ if (this.dataManager.addRegistry(data.type)) {
504
+ const proxy = this.dataManager.getExistingProxy(data.type);
505
+ return proxy as Ctr;
506
+ }
507
+
508
+ if (this.queueManager.handlePopupQueue(layerData, this.dataManager.getLayerMap())) {
509
+ return undefined;
510
+ }
511
+
512
+ this.dataManager.addLayerData(data.type, layerData);
513
+
514
+ return this.syncGenerationLayer(layerData, data);
278
515
  }
279
516
 
280
517
  /**
@@ -311,7 +548,9 @@ class FWLayerOpenManager {
311
548
  ): Promise<Ctr> {
312
549
  try {
313
550
  const res = await this.resourceManager.loadLayerAsync(layerData);
314
- return this.createLayer(layerData, res, data) as Ctr;
551
+ const ctr = this.createLayer(layerData, res, data) as Ctr;
552
+ this.dataManager.removeFromRegistry(layerData.controllerConstructor);
553
+ return ctr;
315
554
  } catch (e) {
316
555
  FWLog.error(`asyncGenerationLayer failed:`, e);
317
556
  this.dataManager.clearFailedLayer(layerData);
@@ -328,7 +567,9 @@ class FWLayerOpenManager {
328
567
  ): Ctr {
329
568
  try {
330
569
  const res = this.resourceManager.loadLayerSync(layerData);
331
- return this.createLayer(layerData, res, data);
570
+ const ctr = this.createLayer(layerData, res, data) as Ctr;
571
+ this.dataManager.removeFromRegistry(layerData.controllerConstructor);
572
+ return ctr;
332
573
  } catch (e) {
333
574
  FWLog.error(`syncGenerationLayer failed:`, e);
334
575
  this.dataManager.clearFailedLayer(layerData);
@@ -547,215 +788,3 @@ class FWLayerLifecycleManager {
547
788
  };
548
789
  }
549
790
  }
550
-
551
- export class FWLayerManager extends FWManager implements FW.LayerManager {
552
- private resourceManager: FWLayerResourceManager;
553
- private dataManager: FWLayerDataManager;
554
- private createManager: FWLayerCreateManager;
555
- private stackManager: FWLayerStackManager;
556
- private stateManager: FWLayerStateManager;
557
- private queueManager: FWLayerQueueManager;
558
- private openManager: FWLayerOpenManager;
559
-
560
- public initialize(): void {
561
- this.resourceManager = new FWLayerResourceManager();
562
- this.dataManager = new FWLayerDataManager();
563
- this.createManager = new FWLayerCreateManager();
564
- this.stackManager = new FWLayerStackManager();
565
- this.stateManager = new FWLayerStateManager();
566
- this.queueManager = new FWLayerQueueManager();
567
-
568
- this.openManager = new FWLayerOpenManager(
569
- this.dataManager,
570
- this.resourceManager,
571
- this.createManager,
572
- this.stackManager,
573
- this.queueManager,
574
- );
575
- }
576
-
577
- /**
578
- * 异步打开Layer
579
- */
580
- async openAsync<Ctr extends FW.LayerController = FW.LayerController>(
581
- data: FW.LayerOpenArgs,
582
- ): Promise<Ctr> {
583
- return this.openManager.openLayer(data, true) as Promise<Ctr>;
584
- }
585
-
586
- /**
587
- * 同步打开
588
- */
589
- openSync<Ctr extends FW.LayerController = FW.LayerController>(data: FW.LayerOpenArgs): Ctr {
590
- return this.openManager.openLayer(data, false) as unknown as Ctr;
591
- }
592
-
593
- /**
594
- * 显示layer并恢复所有节点事件
595
- */
596
- displayLayer<Ctr extends FW.LayerController = FW.LayerController>(ctr: Ctr): Ctr {
597
- const layerData = ctr.layerData;
598
-
599
- if (!this.dataManager.getLayerMap().has(ctr.layerData.controllerConstructor)) {
600
- FWLog.warn(`display layer failed,layer name : ${layerData.layerName}`);
601
- return;
602
- }
603
- /** 非常驻layer不允许操作透明度显示 */
604
- if (ctr.layerType != FWSystemDefine.FWLayerType.PERMANENT) return;
605
-
606
- const node = ctr.layer.node;
607
- node.opacity = 255;
608
- node.resumeSystemEvents(true);
609
-
610
- FW.Entry.evtMgr.targetResume(ctr);
611
- FW.Entry.timeMgr.resumeSchedule(ctr);
612
-
613
- return ctr;
614
- }
615
-
616
- /**
617
- * 隐藏layer并隐藏所有节点事件
618
- */
619
- hideLayer<Ctr extends FW.LayerController = FW.LayerController>(ctr: Ctr): Ctr {
620
- const layerData = ctr.layerData;
621
- if (!this.dataManager.getLayerMap().has(ctr.layerData.controllerConstructor)) {
622
- FWLog.warn(`hide layer failed,layer name : ${layerData.layerName}`);
623
- return;
624
- }
625
-
626
- /** 非常驻layer不允许操作透明度 */
627
- if (ctr.layerType != FWSystemDefine.FWLayerType.PERMANENT) return;
628
-
629
- const node = ctr.layer.node;
630
- node.opacity = 0;
631
- node.pauseSystemEvents(true);
632
- FW.Entry.evtMgr.targetPause(ctr);
633
- FW.Entry.timeMgr.pauseSchedule(ctr);
634
-
635
- return ctr;
636
- }
637
-
638
- /**
639
- * 通过layer名字关闭
640
- */
641
- closeFromLayerName(name: string | string[]): void {
642
- this.dataManager.getLayerMap().forEach((v) => {
643
- if (Array.isArray(name)) {
644
- name.forEach((n) => {
645
- if (n === v.layerName) {
646
- this.close(v.controller);
647
- }
648
- });
649
- } else {
650
- if (v.layerName == name) {
651
- this.close(v.controller);
652
- }
653
- }
654
- });
655
- }
656
-
657
- /**
658
- * 从栈关闭
659
- */
660
- closeFromStack(count?: number) {
661
- count = count ? count : 1;
662
- for (let i = 0; i < count; i++) {
663
- let layerData = this.stackManager.pop();
664
- let ctr = layerData.controller;
665
- if (!this.dataManager.getLayerMap().has(layerData.controllerConstructor)) {
666
- return;
667
- }
668
- if (cc.isValid(ctr.layer?.node)) {
669
- ctr.layer.destroy?.();
670
- if (ctr.autoRelease) {
671
- FW.Entry.resMgr.releaseAsset(ctr.layerData.layerAssetProperty);
672
- }
673
- this.dataManager.notifyExternalRefUpdates(ctr.layerData);
674
- }
675
- this.dataManager.removeFromMap(layerData.controllerConstructor);
676
- }
677
- }
678
- /**
679
- * 移除指定Layer所有子Layer
680
- * @param layer
681
- * @returns
682
- */
683
- async removeAllChildren(node: cc.Node) {
684
- if (!cc.isValid(node)) return;
685
- const layers = node.getComponentsInChildren(FWLayer);
686
- layers.forEach((v) => {
687
- if (cc.isValid(v?.node)) {
688
- v?.ctr?.close();
689
- }
690
- });
691
- }
692
-
693
- /**
694
- * 关闭layer
695
- */
696
- async close<Ctr extends FW.LayerController = FW.LayerController>(
697
- ctr: Ctr,
698
- ): Promise<FW.LayerController> {
699
- if (!ctr) return;
700
-
701
- let layerData = ctr.layerData;
702
-
703
- if (cc.isValid(ctr.layer?.node)) {
704
- await ctr.onClose?.();
705
- ctr.destroy?.();
706
- if (ctr.autoRelease) {
707
- FW.Entry.resMgr.releaseAsset(ctr.layerData.layerAssetProperty);
708
- }
709
- this.dataManager.notifyExternalRefUpdates(ctr.layerData);
710
- }
711
-
712
- this.dataManager.removeFromMap(layerData.controllerConstructor);
713
- this.dataManager.removeFromRegistry(ctr.layerData.controllerConstructor);
714
-
715
- const index = this.stackManager.getStack().findIndex((v) => {
716
- v.controller == ctr;
717
- });
718
- if (index > -1) {
719
- this.stackManager.getStack().splice(index, 1);
720
- }
721
-
722
- /** 如果队列中还有等待打开的layer */
723
- if (!this.queueManager.isEmpty()) {
724
- const nextLayerData = this.queueManager.getNextLayer();
725
- /** 先尝试同步打开 */
726
- const nextLayer = this.openSync({
727
- parent: nextLayerData.layerParent,
728
- position: nextLayerData.layerPosition,
729
- type: nextLayerData.controllerConstructor,
730
- });
731
- /** 如果同步打开失败,再次尝试异步打开(可能由于资源所在bundle并未提前加载) */
732
- if (!nextLayer) {
733
- return this.openAsync({
734
- parent: nextLayerData.layerParent,
735
- position: nextLayerData.layerPosition,
736
- type: nextLayerData.controllerConstructor,
737
- });
738
- } else {
739
- return nextLayer;
740
- }
741
- } else {
742
- return undefined;
743
- }
744
- }
745
-
746
- getLayerMap(): Map<new () => FW.LayerController, FWLayerData> {
747
- return this.dataManager.getLayerMap();
748
- }
749
-
750
- public clear() {
751
- this.queueManager.clear();
752
- this.stackManager.clear();
753
- this.stateManager.clear();
754
- this.dataManager.clear();
755
- this.dataManager.getLayerMap().forEach((v) => this.close(v.controller));
756
- }
757
-
758
- public onDestroy(): void {
759
- this.clear();
760
- }
761
- }
@@ -1,8 +1,58 @@
1
- export abstract class FWManager {
1
+ import FWLog from '../log/FWLog';
2
+
3
+ export abstract class FWManager implements FW.Manager {
2
4
  public readonly entry: FW.Entry = FW.Entry;
5
+ public readonly managerName: string = this.constructor.name;
6
+
7
+ public abstract initialize(): void;
8
+ public abstract onDestroy(): void;
9
+
3
10
  constructor() {
4
11
  this.initialize();
5
12
  }
6
- public abstract initialize(): void;
7
- public abstract onDestroy(): void;
13
+
14
+ protected async invoke<T>(operation: Promise<T>, operationName: string = 'unknown'): Promise<T> {
15
+ const startTime = this.getCurrentTime();
16
+
17
+ try {
18
+ const result = await operation;
19
+ const duration = this.getCurrentTime() - startTime;
20
+
21
+ this.recordPerformanceMetric(operationName, duration);
22
+ return result;
23
+ } catch (error) {
24
+ this.handleError(operationName, error);
25
+ return undefined;
26
+ }
27
+ }
28
+
29
+ private recordPerformanceMetric(operationName: string, duration: number): void {
30
+ if (FW.Entry.performanceMgr) {
31
+ FW.Entry.performanceMgr.recordOperationMetric(this.managerName, operationName, duration);
32
+ }
33
+
34
+ if (duration > 1000) {
35
+ FWLog.warn(`Operation ${operationName} took ${duration}ms`);
36
+ } else if (FW.Entry.engineMgr.debug) {
37
+ FWLog.debug(`Operation ${operationName} took ${duration}ms`);
38
+ }
39
+ }
40
+
41
+ protected handleError(operation: string, error: any): void {
42
+ const errorInfo = {
43
+ manager: this.managerName,
44
+ operation,
45
+ error: error?.message || error,
46
+ stack: error?.stack,
47
+ };
48
+
49
+ FWLog.error(`Manager error in ${this.managerName}.${operation}:`, errorInfo);
50
+
51
+ if (CC_DEBUG && FW.Entry.engineMgr.debug) {
52
+ }
53
+ }
54
+
55
+ protected getCurrentTime(): number {
56
+ return Date.now();
57
+ }
8
58
  }
@@ -0,0 +1,206 @@
1
+ // FWPerformanceManager.ts
2
+
3
+ import FWLog from '../log/FWLog';
4
+ import { FWManager } from './FWManager';
5
+
6
+ /**
7
+ * 性能管理器
8
+ */
9
+ export class FWPerformanceManager extends FWManager implements FW.PerformanceManager {
10
+ private metrics: FW.PerformanceMetric[] = [];
11
+ private managerStats: Map<
12
+ string,
13
+ {
14
+ totalDuration: number;
15
+ operationCount: number;
16
+ minDuration: number;
17
+ maxDuration: number;
18
+ }
19
+ > = new Map();
20
+
21
+ private performanceOptions: FW.PerformanceManagerOptions;
22
+
23
+ constructor() {
24
+ super();
25
+
26
+ this.performanceOptions = {
27
+ autoCollect: true,
28
+ dataRetentionTime: 5 * 60 * 1000,
29
+ samplingRate: 1.0,
30
+ warningThreshold: 1000,
31
+ };
32
+ }
33
+
34
+ public async initialize(): Promise<void> {
35
+ if (this.performanceOptions.autoCollect) {
36
+ this.startAutoCleanup();
37
+ }
38
+ }
39
+
40
+ public onDestroy(): void {
41
+ this.metrics = [];
42
+ this.managerStats.clear();
43
+ }
44
+
45
+ protected onCleanup(): void {}
46
+
47
+ /**
48
+ * 记录操作性能指标
49
+ */
50
+ public recordOperationMetric(manager: string, operation: string, duration: number): void {
51
+ if (Math.random() > this.performanceOptions.samplingRate!) {
52
+ return;
53
+ }
54
+ const metric: FW.PerformanceMetric = {
55
+ manager,
56
+ operation,
57
+ duration,
58
+ timestamp: Date.now(),
59
+ };
60
+
61
+ this.metrics.push(metric);
62
+ this.updateManagerStats(manager, duration);
63
+
64
+ if (duration > this.performanceOptions.warningThreshold!) {
65
+ FWLog.warn(`Performance warning: ${manager}.${operation} took ${duration}ms`);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * 获取指定管理器的性能报告
71
+ */
72
+ public getManagerReport(manager: string): FW.PerformanceReport | null {
73
+ const stats = this.managerStats.get(manager);
74
+ if (!stats) {
75
+ return null;
76
+ }
77
+
78
+ const recentMetrics = this.metrics.filter((m) => m.manager === manager).slice(-500);
79
+
80
+ return {
81
+ manager,
82
+ totalOperations: stats.operationCount,
83
+ averageDuration: stats.totalDuration / stats.operationCount,
84
+ minDuration: stats.minDuration,
85
+ maxDuration: stats.maxDuration,
86
+ recentMetrics,
87
+ };
88
+ }
89
+
90
+ /**
91
+ * 获取所有管理器的性能报告
92
+ */
93
+ public getAllReports(): Map<string, FW.PerformanceReport> {
94
+ const reports = new Map<string, FW.PerformanceReport>();
95
+
96
+ this.managerStats.forEach((stats, manager) => {
97
+ const recentMetrics = this.metrics.filter((m) => m.manager === manager).slice(-500);
98
+ reports.set(manager, {
99
+ manager,
100
+ totalOperations: stats.operationCount,
101
+ averageDuration: stats.totalDuration / stats.operationCount,
102
+ minDuration: stats.minDuration,
103
+ maxDuration: stats.maxDuration,
104
+ recentMetrics,
105
+ });
106
+ });
107
+
108
+ return reports;
109
+ }
110
+
111
+ /**
112
+ * 获取性能摘要
113
+ */
114
+ public getPerformanceSummary(): {
115
+ totalOperations: number;
116
+ averageOperationTime: number;
117
+ slowestManager: string;
118
+ mostActiveManager: string;
119
+ } {
120
+ let totalOperations = 0;
121
+ let totalDuration = 0;
122
+ let slowestManager = '';
123
+ let maxAvgDuration = 0;
124
+ let mostActiveManager = '';
125
+ let maxOperations = 0;
126
+
127
+ this.managerStats.forEach((stats, manager) => {
128
+ totalOperations += stats.operationCount;
129
+ totalDuration += stats.totalDuration;
130
+
131
+ const avgDuration = stats.totalDuration / stats.operationCount;
132
+ if (avgDuration > maxAvgDuration) {
133
+ maxAvgDuration = avgDuration;
134
+ slowestManager = manager;
135
+ }
136
+
137
+ if (stats.operationCount > maxOperations) {
138
+ maxOperations = stats.operationCount;
139
+ mostActiveManager = manager;
140
+ }
141
+ });
142
+
143
+ return {
144
+ totalOperations,
145
+ averageOperationTime: totalOperations > 0 ? totalDuration / totalOperations : 0,
146
+ slowestManager,
147
+ mostActiveManager,
148
+ };
149
+ }
150
+
151
+ /**
152
+ * 清理数据
153
+ */
154
+ public clearPerformanceData(
155
+ retentionTime: number = this.performanceOptions.dataRetentionTime!,
156
+ ): number {
157
+ const cutoffTime = Date.now() - retentionTime;
158
+ const initialLength = this.metrics.length;
159
+
160
+ this.metrics = this.metrics.filter((metric) => metric.timestamp > cutoffTime);
161
+
162
+ const removedCount = initialLength - this.metrics.length;
163
+ if (removedCount > 0) {
164
+ FWLog.debug(`Cleaned up ${removedCount} old performance records`);
165
+ }
166
+
167
+ return removedCount;
168
+ }
169
+
170
+ /**
171
+ * 重置所有性能数据
172
+ */
173
+ public resetAllData(): void {
174
+ this.metrics = [];
175
+ this.managerStats.clear();
176
+ }
177
+
178
+ /**
179
+ * 更新管理器统计信息
180
+ */
181
+ private updateManagerStats(manager: string, duration: number): void {
182
+ if (!this.managerStats.has(manager)) {
183
+ this.managerStats.set(manager, {
184
+ totalDuration: 0,
185
+ operationCount: 0,
186
+ minDuration: Infinity,
187
+ maxDuration: -Infinity,
188
+ });
189
+ }
190
+
191
+ const stats = this.managerStats.get(manager)!;
192
+ stats.totalDuration += duration;
193
+ stats.operationCount++;
194
+ stats.minDuration = Math.min(stats.minDuration, duration);
195
+ stats.maxDuration = Math.max(stats.maxDuration, duration);
196
+ }
197
+
198
+ /**
199
+ * 启动自动清理任务
200
+ */
201
+ private startAutoCleanup(): void {
202
+ FW.Entry.timeMgr.schedule(() => {
203
+ this.clearPerformanceData();
204
+ }, 300);
205
+ }
206
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "ver": "1.1.0",
3
+ "uuid": "a593b057-a7d5-4dd4-ac81-3c8a70694bd2",
4
+ "importer": "typescript",
5
+ "isPlugin": false,
6
+ "loadPluginInWeb": true,
7
+ "loadPluginInNative": true,
8
+ "loadPluginInEditor": false,
9
+ "subMetas": {}
10
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ives_xxz/framework",
3
- "version": "1.4.12",
3
+ "version": "1.4.14",
4
4
  "description": "cocoscreator 2.x mvc framework",
5
5
  "main": "index.js",
6
6
  "keywords": ["123456"],
@@ -1,7 +1,54 @@
1
+ import FWLog from '../log/FWLog';
2
+
1
3
  export default abstract class FWService {
2
4
  constructor() {
3
5
  this.initialize();
4
6
  }
5
7
  public abstract initialize(): void;
6
8
  public abstract destroy(): void;
9
+ public abstract readonly serviceName: string;
10
+
11
+ protected async invoke<T>(operation: Promise<T>, operationName: string = 'unknown'): Promise<T> {
12
+ const startTime = this.getCurrentTime();
13
+
14
+ try {
15
+ const result = await operation;
16
+ const duration = this.getCurrentTime() - startTime;
17
+
18
+ this.recordPerformanceMetric(operationName, duration);
19
+ return result;
20
+ } catch (error) {
21
+ this.handleError(operationName, error);
22
+ return undefined;
23
+ }
24
+ }
25
+
26
+ private recordPerformanceMetric(operationName: string, duration: number): void {
27
+ if (FW.Entry.performanceMgr) {
28
+ FW.Entry.performanceMgr.recordOperationMetric(this.serviceName, operationName, duration);
29
+ }
30
+
31
+ if (FW.Entry.engineMgr.debug) {
32
+ const log = duration > 1000 ? FWLog.warn : FWLog.debug;
33
+ log(`Operation ${operationName} took ${duration}ms`);
34
+ }
35
+ }
36
+
37
+ protected getCurrentTime(): number {
38
+ return Date.now();
39
+ }
40
+
41
+ protected handleError(operation: string, error: any): void {
42
+ const errorInfo = {
43
+ manager: this.serviceName,
44
+ operation,
45
+ error: error?.message || error,
46
+ stack: error?.stack,
47
+ };
48
+
49
+ FWLog.error(`Manager error in ${this.serviceName}.${operation}:`, errorInfo);
50
+
51
+ if (FW.Entry.engineMgr.debug) {
52
+ }
53
+ }
7
54
  }
@@ -3,6 +3,7 @@ import FWLog from '../../log/FWLog';
3
3
  import FWService from '../FWService';
4
4
 
5
5
  export default class FWHttp extends FWService {
6
+ public serviceName: string = 'HTTP';
6
7
  public initialize(): void {}
7
8
  public destroy(): void {}
8
9
 
@@ -10,47 +11,62 @@ export default class FWHttp extends FWService {
10
11
  url: string,
11
12
  params?: string,
12
13
  cb?: (response: string) => void,
14
+ tag?: string,
13
15
  ): Promise<string> {
14
- return this.dataProcessing(url, params, cb, FWSystemDefine.FWHttpRequestType.GET);
16
+ return this.dataProcessing(url, params, cb, tag, FWSystemDefine.FWHttpRequestType.GET);
15
17
  }
16
18
 
17
19
  protected async postMessage(
18
20
  url: string,
19
21
  params?: string,
20
22
  cb?: (response: string) => void,
23
+ tag?: string,
21
24
  ): Promise<string> {
22
- return this.dataProcessing(url, params, cb, FWSystemDefine.FWHttpRequestType.POST);
25
+ return this.dataProcessing(url, params, cb, tag, FWSystemDefine.FWHttpRequestType.POST);
23
26
  }
24
27
 
25
- private dataProcessing(
28
+ private async dataProcessing(
26
29
  url: string,
27
30
  params: string,
28
31
  cb: (response: any) => void,
32
+ tag: string,
29
33
  type: FWSystemDefine.FWHttpRequestType,
30
34
  ): Promise<string> {
31
- return new Promise((resolve: (msg: string) => void, reject: (error: string) => void) => {
32
- const xhr = new XMLHttpRequest();
33
- xhr.onreadystatechange = () => {
34
- if (xhr.readyState == 4 && xhr.status === 200) {
35
- cb?.(xhr.response);
36
- resolve(xhr.response);
37
- }
38
- };
39
-
40
- xhr.onerror = (err: any) => {
41
- FWLog.error(err);
42
- this.onError(err);
43
- reject(`http request error:${err}`);
44
- };
45
-
46
- xhr.ontimeout = () => {
47
- this.onTimeout();
48
- reject(`http request timeout!`);
49
- };
50
-
51
- xhr.open(type, url, true);
52
- xhr.send(params);
53
- });
35
+ let xhr: XMLHttpRequest;
36
+ return await this.invoke(
37
+ FW.Entry.promiseMgr.execute<string>(
38
+ (resolve, reject) => {
39
+ xhr = new XMLHttpRequest();
40
+ xhr.onreadystatechange = () => {
41
+ if (xhr.readyState == 4 && xhr.status === 200) {
42
+ cb?.(xhr.response);
43
+ resolve(xhr.response);
44
+ }
45
+ };
46
+
47
+ xhr.onerror = (err: any) => {
48
+ FWLog.error(err);
49
+ this.onError(err);
50
+ reject(`http request error:${err}`);
51
+ };
52
+
53
+ xhr.ontimeout = () => {
54
+ this.onTimeout();
55
+ reject(`http request timeout!`);
56
+ };
57
+
58
+ xhr.open(type, url, true);
59
+ xhr.send(params);
60
+ },
61
+ {
62
+ retryCount: 3,
63
+ retryCondition(error, retryCount) {
64
+ return xhr.readyState != 4 || (xhr.status !== 200 && retryCount < 3);
65
+ },
66
+ },
67
+ ).promise,
68
+ tag ? `http request ->${tag}` : '',
69
+ );
54
70
  }
55
71
 
56
72
  onError?(err: any);
package/utils/FWTask.ts CHANGED
@@ -182,7 +182,7 @@ export default class FWTask implements FW.Task {
182
182
  requestAnimationFrame(async () => await this.executeFrame());
183
183
  }
184
184
 
185
- getPerformanceReport(): FW.PerformanceReport {
185
+ getPerformanceReport(): FW.TaskPerformanceReport {
186
186
  const frameTimes = this.performanceData.frameTimes;
187
187
  const avgFrameTime = frameTimes.reduce((sum, t) => sum + t, 0) / frameTimes.length || 0;
188
188