Skip to content

Commit dec508e

Browse files
author
qiuguohua
committed
Refactoring worker-ui communication
1 parent 7416a24 commit dec508e

File tree

10 files changed

+1251
-422
lines changed

10 files changed

+1251
-422
lines changed

templates/harmonyos-next/entry/src/main/ets/common/CallbacksInvoker.ts

Lines changed: 406 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Copyright (c) 2013-2016 Chukong Technologies Inc.
3+
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
4+
5+
http://www.cocos.com
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights to
10+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11+
of the Software, and to permit persons to whom the Software is furnished to do so,
12+
subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
*/
25+
26+
import { Eventify } from './eventify';
27+
28+
class Empty { }
29+
30+
/**
31+
* @en
32+
* EventTarget is an object to which an event is dispatched when something has occurred.
33+
* [[Node]]s are the most common event targets, but other objects can be event targets too.
34+
* If a class cannot extend from EventTarget, it can consider using [[Eventify]].
35+
*
36+
* @zh
37+
* 事件目标是具有注册监听器、派发事件能力的类,[[Node]] 是最常见的事件目标,
38+
* 但是其他类也可以继承自事件目标以获得管理监听器和派发事件的能力。
39+
* 如果无法继承自 EventTarget,也可以使用 [[Eventify]]
40+
*/
41+
export const EventTarget = Eventify(Empty);
42+
43+
export type EventTarget = InstanceType<typeof EventTarget>;
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
3+
4+
https://www.cocos.com/
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights to
9+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10+
of the Software, and to permit persons to whom the Software is furnished to do so,
11+
subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
23+
*/
24+
25+
import { CallbacksInvoker } from './CallbacksInvoker';
26+
import { createMap } from './utils';
27+
28+
type Constructor<T> = new (...args: any[]) => T;
29+
30+
type EventType = string | number;
31+
32+
/**
33+
* @zh
34+
* 实现该接口的对象具有处理事件的能力。
35+
* @en
36+
* Objects those implement this interface have essentially the capability to process events.
37+
*/
38+
export interface IEventified {
39+
/**
40+
* @zh 检查指定事件是否已注册回调。
41+
* @en Checks whether there is correspond event listener registered on the given event.
42+
* @param type - Event type.
43+
* @param callback - Callback function when event triggered.
44+
* @param target - Callback callee.
45+
*/
46+
hasEventListener(type: string, callback?: (...args: any[]) => void, target?: any): boolean;
47+
48+
/**
49+
* @en
50+
* Register an callback of a specific event type on the EventTarget.
51+
* This type of event should be triggered via `emit`.
52+
* @zh
53+
* 注册事件目标的特定事件类型回调。这种类型的事件应该被 `emit` 触发。
54+
*
55+
* @param type - A string representing the event type to listen for.
56+
* @param callback - The callback that will be invoked when the event is dispatched.
57+
* The callback is ignored if it is a duplicate (the callbacks are unique).
58+
* @param thisArg - The target (this object) to invoke the callback, can be null
59+
* @return - Just returns the incoming callback so you can save the anonymous function easier.
60+
* @example
61+
* import { log } from 'cc';
62+
* eventTarget.on('fire', function () {
63+
* log("fire in the hole");
64+
* }, node);
65+
*/
66+
on<TFunction extends (...args: any[]) => void>(type: EventType, callback: TFunction, thisArg?: any, once?: boolean): typeof callback;
67+
68+
/**
69+
* @en
70+
* Register an callback of a specific event type on the EventTarget,
71+
* the callback will remove itself after the first time it is triggered.
72+
* @zh
73+
* 注册事件目标的特定事件类型回调,回调会在第一时间被触发后删除自身。
74+
*
75+
* @param type - A string representing the event type to listen for.
76+
* @param callback - The callback that will be invoked when the event is dispatched.
77+
* The callback is ignored if it is a duplicate (the callbacks are unique).
78+
* @param target - The target (this object) to invoke the callback, can be null
79+
* @example
80+
* import { log } from 'cc';
81+
* eventTarget.once('fire', function () {
82+
* log("this is the callback and will be invoked only once");
83+
* }, node);
84+
*/
85+
once<TFunction extends (...args: any[]) => void>(type: EventType, callback: TFunction, thisArg?: any): typeof callback;
86+
87+
/**
88+
* @en
89+
* Removes the listeners previously registered with the same type, callback, target and or useCapture,
90+
* if only type is passed as parameter, all listeners registered with that type will be removed.
91+
* @zh
92+
* 删除之前用同类型,回调,目标或 useCapture 注册的事件监听器,如果只传递 type,将会删除 type 类型的所有事件监听器。
93+
*
94+
* @param type - A string representing the event type being removed.
95+
* @param callback - The callback to remove.
96+
* @param target - The target (this object) to invoke the callback, if it's not given, only callback without target will be removed
97+
* @example
98+
* import { log } from 'cc';
99+
* // register fire eventListener
100+
* var callback = eventTarget.on('fire', function () {
101+
* log("fire in the hole");
102+
* }, target);
103+
* // remove fire event listener
104+
* eventTarget.off('fire', callback, target);
105+
* // remove all fire event listeners
106+
* eventTarget.off('fire');
107+
*/
108+
off<TFunction extends (...args: any[]) => void>(type: EventType, callback?: TFunction, thisArg?: any): void;
109+
110+
/**
111+
* @en Removes all callbacks previously registered with the same target (passed as parameter).
112+
* This is not for removing all listeners in the current event target,
113+
* and this is not for removing all listeners the target parameter have registered.
114+
* It's only for removing all listeners (callback and target couple) registered on the current event target by the target parameter.
115+
* @zh 在当前 EventTarget 上删除指定目标(target 参数)注册的所有事件监听器。
116+
* 这个函数无法删除当前 EventTarget 的所有事件监听器,也无法删除 target 参数所注册的所有事件监听器。
117+
* 这个函数只能删除 target 参数在当前 EventTarget 上注册的所有事件监听器。
118+
* @param typeOrTarget - The target to be searched for all related listeners
119+
*/
120+
targetOff(typeOrTarget: any): void;
121+
122+
/**
123+
* @zh 移除在特定事件类型中注册的所有回调或在某个目标中注册的所有回调。
124+
* @en Removes all callbacks registered in a certain event type or all callbacks registered with a certain target
125+
* @param typeOrTarget - The event type or target with which the listeners will be removed
126+
*/
127+
removeAll(typeOrTarget: any): void;
128+
129+
/**
130+
* @zh 派发一个指定事件,并传递需要的参数
131+
* @en Trigger an event directly with the event name and necessary arguments.
132+
* @param type - event type
133+
* @param args - Arguments when the event triggered
134+
*/
135+
emit(type: EventType, arg0?: any, arg1?: any, arg2?: any, arg3?: any, arg4?: any, arg5?: any, arg6?: any, arg7?: any, arg8?: any, arg9?: any,
136+
arg10?: any, arg11?: any, arg12?: any, arg13?: any, arg14?: any, arg15?: any, arg16?: any, arg17?: any, arg18?: any): any;
137+
}
138+
139+
/**
140+
* @en Generate a new class from the given base class, after polyfill all functionalities in [[IEventified]] as if it's extended from [[EventTarget]]
141+
* @zh 生成一个类,该类继承自指定的基类,并以和 [[EventTarget]] 等同的方式实现了 [[IEventified]] 的所有接口。
142+
* @param base The base class
143+
* @example
144+
* ```ts
145+
* class Base { say() { console.log('Hello!'); } }
146+
* class MyClass extends Eventify(Base) { }
147+
* function (o: MyClass) {
148+
* o.say(); // Ok: Extend from `Base`
149+
* o.emit('sing', 'The ghost'); // Ok: `MyClass` implements IEventified
150+
* }
151+
* ```
152+
*/
153+
export function Eventify<TBase>(base: Constructor<TBase>): Constructor<TBase & IEventified> {
154+
class Eventified extends (base as unknown as any) {
155+
/**
156+
* @dontmangle
157+
* NOTE: Eventified mixins all properties from CallbacksInvoker.prototype in the following code.
158+
* After invoking `Eventify` for a class, CallbacksInvoker's constructor will not be called,
159+
* but its functions may invoke `this._callbackTable` which is declared as `public` in CallbacksInvoker.
160+
* Marking it as dontmangle is a workaround to avoid the issue that `this._callbackTable` is not defined.
161+
*/
162+
protected _callbackTable = createMap(true);
163+
164+
public once<Callback extends (...any) => void>(type: EventType, callback: Callback, target?: any): Callback {
165+
return this.on(type, callback, target, true) as Callback;
166+
}
167+
168+
public targetOff(typeOrTarget: any): void {
169+
this.removeAll(typeOrTarget);
170+
}
171+
}
172+
173+
// Mixin with `CallbacksInvokers`'s prototype
174+
const callbacksInvokerPrototype = CallbacksInvoker.prototype;
175+
const propertyKeys: (string | symbol)[] = (Object.getOwnPropertyNames(callbacksInvokerPrototype) as (string | symbol)[]).concat(
176+
Object.getOwnPropertySymbols(callbacksInvokerPrototype),
177+
);
178+
for (let iPropertyKey = 0; iPropertyKey < propertyKeys.length; ++iPropertyKey) {
179+
const propertyKey = propertyKeys[iPropertyKey];
180+
if (!(propertyKey in Eventified.prototype)) {
181+
const propertyDescriptor = Object.getOwnPropertyDescriptor(callbacksInvokerPrototype, propertyKey);
182+
if (propertyDescriptor) {
183+
Object.defineProperty(Eventified.prototype, propertyKey, propertyDescriptor);
184+
}
185+
}
186+
}
187+
188+
return Eventified as unknown as Constructor<TBase & IEventified>;
189+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
3+
4+
https://www.cocos.com/
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights to
9+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10+
of the Software, and to permit persons to whom the Software is furnished to do so,
11+
subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
23+
*/
24+
25+
/**
26+
* @en Typed object pool.
27+
* It's a traditional design, you can get elements out of the pool or recycle elements by putting back into the pool.
28+
* @zh 支持类型的对象池。这是一个传统设计的对象池,你可以从对象池中取出对象或是放回不再需要对象来复用。
29+
* @see [[RecyclePool]]
30+
*/
31+
export class Pool<T> {
32+
private declare _ctor: () => T;
33+
private declare _elementsPerBatch: number;
34+
private declare _shrinkThreshold: number;
35+
private declare _nextAvail: number;
36+
private _freePool: T[] = [];
37+
private declare _dtor: ((obj: T) => void) | null;
38+
39+
/**
40+
* @en Constructor with the allocator of elements and initial pool size.
41+
* @zh 使用元素的构造器和初始大小的构造函数。
42+
* @param ctor @en The allocator of elements in pool, it's invoked directly without `new` in Pool.
43+
* @zh 元素的构造器,Pool 内部使用该构造器直接创建实例。
44+
* @param elementsPerBatch @en Initial pool size, this size will also be the incremental size when
45+
* the pool is overloaded.
46+
* @zh 对象池的初始大小。当对象池扩容时,也会使用该值。
47+
* @param dtor @en The finalizer of element, it's invoked when this Pool is destroyed or shrunk if
48+
* it is valid.
49+
* @zh 元素的析构器。如果存在的话,当对象池销毁或者缩容时,会使用该析构器。
50+
* @param shrinkThreshold @en The container is shrink only if the size of the container exceeds the shrinkThreshold,
51+
* and the size of the container after reduction is greater than or equal to the shrinkThreshold. The value equals elementsPerBatch
52+
* if not value is passed.
53+
* @zh 只有容器的数量大于 shrinkThreshold 时才缩容,缩减后的容器大小小于等于 shrinkThreshold。如果没有传入值,那么它的值和 elementsPerBatch 相同。
54+
*/
55+
constructor (ctor: () => T, elementsPerBatch: number, dtor?: (obj: T) => void, shrinkThreshold?: number) {
56+
this._ctor = ctor;
57+
this._dtor = dtor || null;
58+
this._elementsPerBatch = Math.max(elementsPerBatch, 1);
59+
this._shrinkThreshold = shrinkThreshold ? Math.max(shrinkThreshold, 1) : this._elementsPerBatch;
60+
this._nextAvail = this._elementsPerBatch - 1;
61+
62+
for (let i = 0; i < this._elementsPerBatch; ++i) {
63+
this._freePool.push(ctor());
64+
}
65+
}
66+
67+
/**
68+
* @en Take an object out of the object pool.
69+
* @zh 从对象池中取出一个对象。
70+
* @returns @en An object ready for use. This function always returns an object.
71+
* @zh 该函数总是返回一个可用的对象。
72+
*/
73+
public alloc (): T {
74+
if (this._nextAvail < 0) {
75+
this._freePool.length = this._elementsPerBatch;
76+
for (let i = 0; i < this._elementsPerBatch; i++) {
77+
this._freePool[i] = this._ctor();
78+
}
79+
this._nextAvail = this._elementsPerBatch - 1;
80+
}
81+
82+
return this._freePool[this._nextAvail--];
83+
}
84+
85+
/**
86+
* @en Put an object back into the object pool.
87+
* @zh 将一个对象放回对象池中。
88+
* @param obj @en The object to be put back into the pool.
89+
* @zh 放回对象池中的对象。
90+
*/
91+
public free (obj: T): void {
92+
this._freePool[++this._nextAvail] = obj;
93+
}
94+
95+
/**
96+
* @en Put multiple objects back into the object pool.
97+
* @zh 将一组对象放回对象池中。
98+
* @param objs @en An array of objects to be put back into the pool.
99+
* @zh 放回对象池中的一组对象。
100+
*/
101+
public freeArray (objs: T[]): void {
102+
this._freePool.length = this._nextAvail + 1;
103+
Array.prototype.push.apply(this._freePool, objs);
104+
this._nextAvail += objs.length;
105+
}
106+
107+
/**
108+
* @en Try to shrink the object pool to reduce memory usage.
109+
* @zh 尝试缩容对象池,以释放内存。
110+
*/
111+
public tryShrink (): void {
112+
const freeObjectNumber = this._nextAvail + 1;
113+
if (freeObjectNumber <= this._shrinkThreshold) {
114+
return;
115+
}
116+
117+
let objectNumberToShrink = 0;
118+
if (freeObjectNumber >> 1 >= this._shrinkThreshold) {
119+
objectNumberToShrink = freeObjectNumber >> 1;
120+
} else {
121+
objectNumberToShrink = Math.floor((freeObjectNumber - this._shrinkThreshold + 1) / 2);
122+
}
123+
124+
if (this._dtor) {
125+
for (let i = this._nextAvail - objectNumberToShrink + 1; i <= this._nextAvail; ++i) {
126+
this._dtor(this._freePool[i]);
127+
}
128+
}
129+
this._nextAvail -= objectNumberToShrink;
130+
this._freePool.length = this._nextAvail + 1;
131+
}
132+
133+
/**
134+
* @en Destroy all elements and clear the pool.
135+
* @zh 释放对象池中所有资源并清空缓存池。
136+
*/
137+
public destroy (): void {
138+
const dtor = arguments.length > 0 ? arguments[0] : null;
139+
if (dtor) {
140+
console.warn("Pool.destroy no longer take a function as parameter, Please specify destruct function in the construction of Pool instead");
141+
return;
142+
}
143+
const readDtor = dtor || this._dtor;
144+
if (readDtor) {
145+
for (let i = 0; i <= this._nextAvail; i++) {
146+
readDtor(this._freePool[i]);
147+
}
148+
}
149+
this._freePool.length = 0;
150+
this._nextAvail = -1;
151+
}
152+
}

0 commit comments

Comments
 (0)