@ives_xxz/framework 1.4.3 → 1.4.5

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
@@ -34,6 +34,7 @@ declare namespace FW {
34
34
  engineMgr: EngineManager;
35
35
  taskMgr: TaskManager;
36
36
  hotUpdateMgr: HotUpdateManager;
37
+ promiseMgr: PromiseManager;
37
38
  scene: Scene;
38
39
  bundleName: string;
39
40
  getComponent<T>(serviceIdentifier: FW.ServiceIdentifier<T>): T;
@@ -48,6 +49,17 @@ declare namespace FW {
48
49
  onDestroy(): void;
49
50
  };
50
51
 
52
+ type PromiseManager = {
53
+ public execute<T = any>(
54
+ executor: (
55
+ resolve: (value: T | PromiseLike<T>) => void,
56
+ reject: (reason?: any) => void,
57
+ signal: AbortSignal,
58
+ ) => void = PromiseExcutor,
59
+ options: PromiseExecuteOptions = {},
60
+ ): PromiseProxy<T>;
61
+ };
62
+
51
63
  type Registry = {
52
64
  /** 注册 */
53
65
  register(): void;
@@ -1910,6 +1922,41 @@ declare namespace FW {
1910
1922
  percentages: number;
1911
1923
  };
1912
1924
 
1925
+ type PromiseProxy<T = Promise> = {
1926
+ id: number;
1927
+ promise: Promise<T>;
1928
+ status: any;
1929
+ abortController: AbortController;
1930
+ abort?: (reason?: any) => void;
1931
+ addAbortEventListener?: (
1932
+ listener: (this: AbortSignal, ev: Event) => any,
1933
+ options?: boolean | AddEventListenerOptions,
1934
+ ) => void;
1935
+ };
1936
+
1937
+ type PromiseExcutor<T> = (
1938
+ resolve: (value: T | PromiseLike<T>) => void,
1939
+ reject: (reason?: any) => void,
1940
+ signal: AbortSignal,
1941
+ ) => void;
1942
+
1943
+ type PromiseExecuteOptions = {
1944
+ timeout?: number;
1945
+ retryCount?: number;
1946
+ retryInterval?: number;
1947
+ retryCondition?: (error: any, retryCount: number) => boolean;
1948
+ };
1949
+
1950
+ type Promise = (resolve: (value: any) => void, reject: (reason?: any) => void) => void;
1951
+
1952
+ type PromiseResult<T = any> = {
1953
+ success: T[];
1954
+ failed: { id: number; reason: any }[];
1955
+ cancelled: number[];
1956
+ };
1957
+
1958
+ type PromiseStatus = 'pending' | 'fulfilled' | 'rejected' | 'cancelled';
1959
+
1913
1960
  declare function timeScale(scale: number);
1914
1961
  declare let Entry: Entry;
1915
1962
  }
@@ -130,4 +130,11 @@ export namespace FWSystemDefine {
130
130
  SPRITE = 'sprite',
131
131
  SKELETON = 'skeleton',
132
132
  }
133
+
134
+ export enum FWPromiseStatus {
135
+ PENDING = 'pending',
136
+ FULFILLED = 'fulfilled',
137
+ REJECTED = 'rejected',
138
+ CANCELLED = 'cancelled',
139
+ }
133
140
  }
package/entry/FWEntry.ts CHANGED
@@ -18,6 +18,7 @@ import { FWEventDefine } from '../define/FWEventDefine';
18
18
  import FWTaskManager from '../manager/FWTaskManager';
19
19
  import FWEngineManager from '../manager/FWEngineManager';
20
20
  import FWHotUpdateManager from '../manager/FWHotUpdateManager';
21
+ import FWPromiseManager from '../manager/FWPromiseManager';
21
22
 
22
23
  /**
23
24
  * 入口脚本
@@ -84,6 +85,10 @@ export default class FWEntry implements FW.Entry {
84
85
  * 热更新管理器
85
86
  */
86
87
  hotUpdateMgr: FW.HotUpdateManager;
88
+ /**
89
+ * promise管理器
90
+ */
91
+ promiseMgr: FW.PromiseManager;
87
92
  /**
88
93
  * 当前Scene
89
94
  */
@@ -113,6 +118,7 @@ export default class FWEntry implements FW.Entry {
113
118
  this.componentMgr = new FWComponentManager();
114
119
  this.languageMgr = new FWLanguageManager();
115
120
  this.hotUpdateMgr = new FWHotUpdateManager();
121
+ this.promiseMgr = new FWPromiseManager();
116
122
 
117
123
  this.resMgr.initialize();
118
124
  this.layerMgr.initialize();
@@ -131,41 +131,36 @@ export class FWAssetManager extends FWManager implements FW.AssetManager {
131
131
 
132
132
  assetData.loaded = false;
133
133
 
134
- return new Promise(
135
- (
136
- resolve: (value: FW.AssetData | PromiseLike<FW.AssetData>) => void,
137
- reject: (reason?: any) => void,
138
- ) => {
139
- const self = this;
140
- bundle.load(
141
- path,
142
- type,
143
- (finish: number, total: number, item: cc.AssetManager.RequestItem) => {
144
- progress?.(finish, total, item);
145
- },
146
- (err: Error, asset: cc.Asset) => {
147
- if (err || !asset) {
148
- FWLog.error(`加载资源失败:${asset},请检查!`);
149
- reject(err);
150
- }
151
-
152
- assetData.loaded = true;
153
- assetData.dependentBundle = bundleName;
154
- assetData.uuid = asset['_uuid'];
155
- assetData.autoRelease = autoRelease;
156
- assetData.asset = asset;
157
- assetData.user = assetProperty.user;
158
- assetData.refCount = 1;
159
- assetData.assetProperty = assetProperty;
160
-
161
- self.assetsMap.set(key, assetData);
134
+ return new Promise((resolve, reject) => {
135
+ const self = this;
136
+ bundle.load(
137
+ path,
138
+ type,
139
+ (finish: number, total: number, item: cc.AssetManager.RequestItem) => {
140
+ progress?.(finish, total, item);
141
+ },
142
+ (err: Error, asset: cc.Asset) => {
143
+ if (err || !asset) {
144
+ reject(err);
145
+ return;
146
+ }
162
147
 
163
- cb?.(assetData);
164
- resolve(assetData);
165
- },
166
- );
167
- },
168
- );
148
+ assetData.loaded = true;
149
+ assetData.dependentBundle = bundleName;
150
+ assetData.uuid = asset['_uuid'];
151
+ assetData.autoRelease = autoRelease;
152
+ assetData.asset = asset;
153
+ assetData.user = assetProperty.user;
154
+ assetData.refCount = 1;
155
+ assetData.assetProperty = assetProperty;
156
+
157
+ self.assetsMap.set(key, assetData);
158
+
159
+ cb?.(assetData);
160
+ resolve(assetData);
161
+ },
162
+ );
163
+ });
169
164
  }
170
165
  /**
171
166
  * 加载文件夹
@@ -0,0 +1,244 @@
1
+ import { FWSystemDefine } from '../define/FWSystemDefine';
2
+ import FWLog from '../log/FWLog';
3
+ import { FWManager } from './FWManager';
4
+
5
+ export default class FWPromiseManager extends FWManager implements FW.PromiseManager {
6
+ private promiseRegistry: Map<number, FW.PromiseProxy>;
7
+ private uniqueId: number = 0;
8
+ private timerSchedule: FW.TimerSchedule;
9
+
10
+ public initialize(): void {
11
+ this.promiseRegistry = new Map<number, FW.PromiseProxy>();
12
+ }
13
+
14
+ public onDestroy(): void {
15
+ this.cancelAll('Manager destroyed');
16
+ this.promiseRegistry.clear();
17
+ this.promiseRegistry = null;
18
+ }
19
+
20
+ /** 创建Promise执行器 */
21
+ public execute<T = any>(
22
+ executor: FW.PromiseExcutor<T>,
23
+ options: FW.PromiseExecuteOptions = {},
24
+ ): FW.PromiseProxy<T> {
25
+ const id = this.uniqueId++;
26
+ const abortController = new AbortController();
27
+ let retryCount = 0;
28
+ let promise: Promise<T>;
29
+ const maxRetryTimes = options.retryCount || 0;
30
+ const retryInterval = options.retryInterval || 0;
31
+ const promiseProxy: FW.PromiseProxy<T> = {
32
+ id,
33
+ promise,
34
+ status: FWSystemDefine.FWPromiseStatus.PENDING,
35
+ abortController,
36
+ };
37
+
38
+ const createPromise = (): Promise<T> => {
39
+ return new Promise<T>((resolve, reject) => {
40
+ if (options.timeout && options.timeout > 0) {
41
+ this.timerSchedule?.unSchedule();
42
+ this.timerSchedule = FW.Entry.timeMgr.scheduleOnce(() => {
43
+ const timeoutError = new Error(`Promise ${id} timeout after ${options.timeout} s`);
44
+ if (
45
+ retryCount < maxRetryTimes &&
46
+ (!options.retryCondition || options.retryCondition(timeoutError, retryCount))
47
+ ) {
48
+ retryCount++;
49
+ FWLog.debug(`Promise ${id} timeout, retrying (${retryCount}/${maxRetryTimes})`);
50
+ if (retryInterval > 0) {
51
+ FW.Entry.timeMgr.scheduleOnce(() => {
52
+ createPromise().then(resolve, reject);
53
+ }, retryInterval);
54
+ } else {
55
+ createPromise().then(resolve, reject);
56
+ }
57
+ } else {
58
+ abortController.abort(timeoutError.message);
59
+ this.timerSchedule?.unSchedule();
60
+ }
61
+ }, options.timeout);
62
+ }
63
+
64
+ const onAbort = () => {
65
+ this.timerSchedule?.unSchedule();
66
+ if (promiseProxy.status === FWSystemDefine.FWPromiseStatus.PENDING) {
67
+ promiseProxy.status = FWSystemDefine.FWPromiseStatus.CANCELLED;
68
+ this.removePromise(id);
69
+ }
70
+ };
71
+
72
+ if (abortController.signal.aborted) {
73
+ onAbort();
74
+ return;
75
+ }
76
+
77
+ abortController.signal.addEventListener('abort', onAbort);
78
+
79
+ const wrappedResolve = (value: T | PromiseLike<T>) => {
80
+ this.timerSchedule?.unSchedule();
81
+ if (promiseProxy.status === FWSystemDefine.FWPromiseStatus.PENDING) {
82
+ promiseProxy.status = FWSystemDefine.FWPromiseStatus.FULFILLED;
83
+ abortController.signal.removeEventListener('abort', onAbort);
84
+ this.removePromise(id);
85
+ resolve(value);
86
+ }
87
+ };
88
+
89
+ const wrappedReject = (reason?: any) => {
90
+ this.timerSchedule?.unSchedule();
91
+ if (
92
+ retryCount < maxRetryTimes &&
93
+ (!options.retryCondition || options.retryCondition(reason, retryCount))
94
+ ) {
95
+ retryCount++;
96
+ FWLog.debug(`Promise ${id} failed, retrying (${retryCount}/${maxRetryTimes}):`, reason);
97
+ if (retryInterval > 0) {
98
+ FW.Entry.timeMgr.scheduleOnce(() => {
99
+ createPromise().then(resolve, reject);
100
+ }, retryInterval);
101
+ } else {
102
+ createPromise().then(resolve, reject);
103
+ }
104
+ } else {
105
+ if (promiseProxy.status === FWSystemDefine.FWPromiseStatus.PENDING) {
106
+ promiseProxy.status = FWSystemDefine.FWPromiseStatus.REJECTED;
107
+ abortController.signal.removeEventListener('abort', onAbort);
108
+ this.removePromise(id);
109
+ reject(reason);
110
+ }
111
+ }
112
+ };
113
+ try {
114
+ executor(wrappedResolve, wrappedReject, abortController.signal);
115
+ } catch (error) {
116
+ wrappedReject(error);
117
+ }
118
+ });
119
+ };
120
+
121
+ promise = createPromise();
122
+ promiseProxy.abort = (reason?: any) => {
123
+ if (promiseProxy.status === FWSystemDefine.FWPromiseStatus.PENDING) {
124
+ FWLog.debug(reason || 'promise cancelled');
125
+ abortController.abort(reason);
126
+ }
127
+ };
128
+ promiseProxy.addAbortEventListener = (
129
+ listener: (this: AbortSignal, ev: Event) => any,
130
+ options?: boolean | AddEventListenerOptions,
131
+ ) => {
132
+ abortController.signal.addEventListener('abort', listener, options);
133
+ };
134
+ this.promiseRegistry.set(id, promiseProxy);
135
+ return promiseProxy;
136
+ }
137
+
138
+ /** 取消指定Promise */
139
+ public cancel(id: number, reason?: any): boolean {
140
+ const promiseProxy = this.promiseRegistry.get(id);
141
+ if (promiseProxy && promiseProxy.status === FWSystemDefine.FWPromiseStatus.PENDING) {
142
+ promiseProxy.abort(reason);
143
+ return true;
144
+ }
145
+ return false;
146
+ }
147
+
148
+ /** 批量取消Promise */
149
+ public cancelMultiple(ids: number[], reason?: any): number[] {
150
+ const cancelled: number[] = [];
151
+ ids.forEach((id) => {
152
+ if (this.cancel(id, reason)) {
153
+ cancelled.push(id);
154
+ }
155
+ });
156
+ return cancelled;
157
+ }
158
+
159
+ /** 取消所有Promise */
160
+ public cancelAll(reason?: any): number[] {
161
+ const cancelled: number[] = [];
162
+ this.promiseRegistry.forEach((promiseProxy, id) => {
163
+ if (promiseProxy.status === FWSystemDefine.FWPromiseStatus.PENDING) {
164
+ promiseProxy.abort(reason);
165
+ cancelled.push(id);
166
+ }
167
+ });
168
+ return cancelled;
169
+ }
170
+
171
+ /** 批量执行Promise并等待所有完成 */
172
+ public async all<T = any>(
173
+ promises: FW.PromiseProxy<T>[],
174
+ options: FW.PromiseExecuteOptions = {},
175
+ ): Promise<FW.PromiseResult<T>> {
176
+ const result: FW.PromiseResult<T> = {
177
+ success: [],
178
+ failed: [],
179
+ cancelled: [],
180
+ };
181
+
182
+ for (const promiseProxy of promises) {
183
+ try {
184
+ const value = await promiseProxy.promise;
185
+ result.success.push(value);
186
+ } catch (error) {
187
+ if (promiseProxy.status === FWSystemDefine.FWPromiseStatus.CANCELLED) {
188
+ result.cancelled.push(promiseProxy.id);
189
+ } else {
190
+ result.failed.push({
191
+ id: promiseProxy.id,
192
+ reason: error,
193
+ });
194
+ }
195
+ }
196
+ }
197
+
198
+ return result;
199
+ }
200
+
201
+ /** 获取Promise状态 */
202
+ public getStatus(id: number): FWSystemDefine.FWPromiseStatus | null {
203
+ const promiseProxy = this.promiseRegistry.get(id);
204
+ return promiseProxy ? promiseProxy.status : null;
205
+ }
206
+
207
+ /** 获取所有Promise状态 */
208
+ public getAllStatus(): Map<number, FWSystemDefine.FWPromiseStatus> {
209
+ const statusMap = new Map<number, FWSystemDefine.FWPromiseStatus>();
210
+ this.promiseRegistry.forEach((promiseProxy, id) => {
211
+ statusMap.set(id, promiseProxy.status);
212
+ });
213
+ return statusMap;
214
+ }
215
+
216
+ /** 移除Promise */
217
+ private removePromise(id: number): void {
218
+ this.promiseRegistry.delete(id);
219
+ }
220
+
221
+ /** 获取正在执行的Promise数量 */
222
+ public getActiveCount(): number {
223
+ return Array.from(this.promiseRegistry.values()).filter(
224
+ (p) => p.status === FWSystemDefine.FWPromiseStatus.PENDING,
225
+ ).length;
226
+ }
227
+
228
+ /** 清理已完成的Promise */
229
+ public clearCompletedPromise(): number {
230
+ const completedIds: number[] = [];
231
+
232
+ this.promiseRegistry.forEach((promiseProxy, id) => {
233
+ if (promiseProxy.status !== FWSystemDefine.FWPromiseStatus.PENDING) {
234
+ completedIds.push(id);
235
+ }
236
+ });
237
+
238
+ completedIds.forEach((id) => {
239
+ this.promiseRegistry.delete(id);
240
+ });
241
+
242
+ return completedIds.length;
243
+ }
244
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "ver": "1.1.0",
3
+ "uuid": "efe0f191-ae87-4773-9dbe-5c66f49670db",
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.3",
3
+ "version": "1.4.5",
4
4
  "description": "cocoscreator 2.x mvc framework",
5
5
  "main": "index.js",
6
6
  "keywords": ["123456"],