@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 +47 -0
- package/define/FWSystemDefine.ts +7 -0
- package/entry/FWEntry.ts +6 -0
- package/manager/FWAssetManager.ts +29 -34
- package/manager/FWPromiseManager.ts +244 -0
- package/manager/FWPromiseManager.ts.meta +10 -0
- package/package.json +1 -1
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
|
}
|
package/define/FWSystemDefine.ts
CHANGED
|
@@ -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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
164
|
-
|
|
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
|
+
}
|