fastevent 1.0.4 → 1.1.1
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/.prettierrc.js +20 -0
- package/.vscode/settings.json +18 -0
- package/CHANGELOG.md +22 -6
- package/dist/devTools.d.mts +308 -0
- package/dist/devTools.d.ts +308 -0
- package/dist/devTools.js +3 -0
- package/dist/devTools.js.map +1 -0
- package/dist/devTools.mjs +3 -0
- package/dist/devTools.mjs.map +1 -0
- package/dist/index.d.mts +40 -17
- package/dist/index.d.ts +40 -17
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/example/README.md +54 -0
- package/example/eslint.config.js +28 -0
- package/example/index.html +13 -0
- package/example/package.json +29 -0
- package/example/pnpm-lock.yaml +2047 -0
- package/example/public/vite.svg +1 -0
- package/example/src/App.css +42 -0
- package/example/src/App.tsx +60 -0
- package/example/src/assets/react.svg +1 -0
- package/example/src/index.css +68 -0
- package/example/src/main.tsx +10 -0
- package/example/src/vite-env.d.ts +1 -0
- package/example/tsconfig.app.json +26 -0
- package/example/tsconfig.json +7 -0
- package/example/tsconfig.node.json +24 -0
- package/example/vite.config.ts +7 -0
- package/package.json +15 -2
- package/readme.md +275 -66
- package/readme_cn.md +275 -70
- package/src/__tests__/emit.test.ts +68 -69
- package/src/__tests__/emitAsync.test.ts +41 -42
- package/src/__tests__/many.test.ts +15 -16
- package/src/__tests__/meta.test.ts +19 -19
- package/src/__tests__/off.test.ts +162 -162
- package/src/__tests__/onany.test.ts +97 -98
- package/src/__tests__/once.test.ts +42 -43
- package/src/__tests__/retain.test.ts +36 -36
- package/src/__tests__/scope.test.ts +38 -39
- package/src/__tests__/types.test.ts +97 -80
- package/src/__tests__/waitFor.test.ts +36 -29
- package/src/__tests__/wildcard.test.ts +114 -115
- package/src/devTools.ts +166 -0
- package/src/event.ts +272 -222
- package/src/scope.ts +64 -55
- package/src/types.ts +38 -34
- package/src/utils/WeakObjectMap.ts +64 -0
- package/tsconfig.json +103 -111
- package/tsup.config.ts +17 -6
package/src/event.ts
CHANGED
|
@@ -1,52 +1,63 @@
|
|
|
1
1
|
import { FastEventScope } from './scope';
|
|
2
|
-
import {
|
|
3
|
-
FastEventListener,
|
|
4
|
-
FastEventOptions,
|
|
5
|
-
FastEvents,
|
|
6
|
-
FastListeners,
|
|
7
|
-
FastListenerNode,
|
|
8
|
-
FastEventSubscriber,
|
|
2
|
+
import {
|
|
3
|
+
FastEventListener,
|
|
4
|
+
FastEventOptions,
|
|
5
|
+
FastEvents,
|
|
6
|
+
FastListeners,
|
|
7
|
+
FastListenerNode,
|
|
8
|
+
FastEventSubscriber,
|
|
9
9
|
ScopeEvents,
|
|
10
|
-
FastEventMeta,
|
|
11
10
|
FastEventListenOptions,
|
|
12
11
|
FastEventMessage
|
|
13
|
-
} from './types';
|
|
12
|
+
} from './types';
|
|
14
13
|
import { isPathMatched } from './utils/isPathMatched';
|
|
15
14
|
import { removeItem } from './utils/removeItem';
|
|
16
|
-
|
|
15
|
+
|
|
17
16
|
export class FastEvent<
|
|
18
|
-
Events extends FastEvents
|
|
19
|
-
Meta extends Record<string,any
|
|
20
|
-
Types extends keyof Events = keyof Events
|
|
21
|
-
>{
|
|
22
|
-
public listeners
|
|
23
|
-
private _options
|
|
24
|
-
private _delimiter
|
|
25
|
-
private _context
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
Events extends FastEvents = FastEvents,
|
|
18
|
+
Meta extends Record<string, any> = Record<string, any>,
|
|
19
|
+
Types extends keyof Events = keyof Events
|
|
20
|
+
> {
|
|
21
|
+
public listeners: FastListeners = { __listeners: [] } as unknown as FastListeners
|
|
22
|
+
private _options: FastEventOptions
|
|
23
|
+
private _delimiter: string = '/'
|
|
24
|
+
private _context: any
|
|
25
|
+
retainedMessages: Map<string, any> = new Map<string, any>()
|
|
26
|
+
listenerCount: number = 0
|
|
27
|
+
constructor(options?: FastEventOptions<Meta>) {
|
|
28
28
|
this._options = Object.assign({
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
debug: false,
|
|
30
|
+
id: Math.random().toString(36).substring(2),
|
|
31
|
+
delimiter: '/',
|
|
32
|
+
context: null,
|
|
33
|
+
ignoreErrors: true
|
|
32
34
|
}, options)
|
|
33
35
|
this._delimiter = this._options.delimiter!
|
|
34
36
|
this._context = this._options.context || this
|
|
37
|
+
this._enableDevTools()
|
|
35
38
|
}
|
|
36
|
-
get options(){ return this._options
|
|
37
|
-
|
|
39
|
+
get options() { return this._options }
|
|
40
|
+
get id() { return this._options.id! }
|
|
41
|
+
private _addListener(parts: string[], listener: FastEventListener<any, any>, options: Required<FastEventListenOptions>): FastListenerNode | undefined {
|
|
38
42
|
const { count, prepend } = options
|
|
39
|
-
return this._forEachNodes(parts,(node)=>{
|
|
40
|
-
const newListener =
|
|
41
|
-
if(prepend){
|
|
42
|
-
node.__listeners.splice(0,0,newListener)
|
|
43
|
-
}else{
|
|
43
|
+
return this._forEachNodes(parts, (node) => {
|
|
44
|
+
const newListener = count > 0 ? [listener, count] : listener as any
|
|
45
|
+
if (prepend) {
|
|
46
|
+
node.__listeners.splice(0, 0, newListener)
|
|
47
|
+
} else {
|
|
44
48
|
node.__listeners.push(newListener)
|
|
45
|
-
}
|
|
46
|
-
if(typeof(this._options.onAddListener)==='function'){
|
|
47
|
-
this._options.onAddListener(parts,listener)
|
|
48
49
|
}
|
|
49
|
-
|
|
50
|
+
if (typeof (this._options.onAddListener) === 'function') {
|
|
51
|
+
this.listenerCount++
|
|
52
|
+
this._options.onAddListener(parts, listener)
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
private _enableDevTools() {
|
|
57
|
+
if (this.options.debug) {
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
globalThis.__FLEXEVENT_DEVTOOLS__.add(this)
|
|
60
|
+
}
|
|
50
61
|
}
|
|
51
62
|
/**
|
|
52
63
|
*
|
|
@@ -56,26 +67,26 @@ export class FastEvent<
|
|
|
56
67
|
* @param callback
|
|
57
68
|
* @returns
|
|
58
69
|
*/
|
|
59
|
-
private _forEachNodes(parts:string[],callback:(node:FastListenerNode,parent:FastListenerNode)=>void):FastListenerNode | undefined{
|
|
60
|
-
if(parts.length === 0) return
|
|
70
|
+
private _forEachNodes(parts: string[], callback: (node: FastListenerNode, parent: FastListenerNode) => void): FastListenerNode | undefined {
|
|
71
|
+
if (parts.length === 0) return
|
|
61
72
|
let current = this.listeners
|
|
62
|
-
for(let i=0;i<parts.length;i++){
|
|
73
|
+
for (let i = 0; i < parts.length; i++) {
|
|
63
74
|
const part = parts[i]
|
|
64
|
-
if(!(part in current)){
|
|
75
|
+
if (!(part in current)) {
|
|
65
76
|
current[part] = {
|
|
66
77
|
__listeners: []
|
|
67
78
|
} as unknown as FastListeners
|
|
68
79
|
}
|
|
69
|
-
if(i===parts.length-1){
|
|
80
|
+
if (i === parts.length - 1) {
|
|
70
81
|
const node = current[part]
|
|
71
|
-
callback(node,current)
|
|
82
|
+
callback(node, current)
|
|
72
83
|
return node
|
|
73
|
-
}else{
|
|
84
|
+
} else {
|
|
74
85
|
current = current[part]
|
|
75
86
|
}
|
|
76
87
|
}
|
|
77
88
|
return undefined
|
|
78
|
-
}
|
|
89
|
+
}
|
|
79
90
|
|
|
80
91
|
|
|
81
92
|
/**
|
|
@@ -85,49 +96,51 @@ export class FastEvent<
|
|
|
85
96
|
* @param listener - 需要移除的事件监听器
|
|
86
97
|
* @description 遍历节点的监听器列表,移除所有匹配的监听器。支持移除普通函数和数组形式的监听器
|
|
87
98
|
*/
|
|
88
|
-
private _removeListener(node: FastListenerNode, path:string[],listener: FastEventListener<any,any,any>): void {
|
|
89
|
-
if(!listener) return
|
|
90
|
-
removeItem(node.__listeners,(item:any)=>{
|
|
91
|
-
item =
|
|
92
|
-
const isRemove = item === listener
|
|
93
|
-
if(isRemove && typeof(this._options.onRemoveListener)==='function'){
|
|
94
|
-
this.
|
|
99
|
+
private _removeListener(node: FastListenerNode, path: string[], listener: FastEventListener<any, any, any>): void {
|
|
100
|
+
if (!listener) return
|
|
101
|
+
removeItem(node.__listeners, (item: any) => {
|
|
102
|
+
item = Array.isArray(item) ? item[0] : item
|
|
103
|
+
const isRemove = item === listener
|
|
104
|
+
if (isRemove && typeof (this._options.onRemoveListener) === 'function') {
|
|
105
|
+
this.listenerCount--
|
|
106
|
+
this._options.onRemoveListener(path, listener)
|
|
95
107
|
}
|
|
96
108
|
return isRemove
|
|
97
|
-
})
|
|
109
|
+
})
|
|
98
110
|
}
|
|
99
|
-
public on<T extends string>(type: T, listener: FastEventListener<T,Events[T],Meta>, options?:FastEventListenOptions
|
|
100
|
-
public on<T extends Types=Types>(type: T, listener: FastEventListener<Types,Events[T],Meta>, options?:FastEventListenOptions): FastEventSubscriber
|
|
101
|
-
public on<P=any>(type: '**', listener: FastEventListener<Types,P,Meta>): FastEventSubscriber
|
|
102
|
-
public on(): FastEventSubscriber{
|
|
111
|
+
public on<T extends string>(type: T, listener: FastEventListener<T, Events[T], Meta>, options?: FastEventListenOptions): FastEventSubscriber
|
|
112
|
+
public on<T extends Types = Types>(type: T, listener: FastEventListener<Types, Events[T], Meta>, options?: FastEventListenOptions): FastEventSubscriber
|
|
113
|
+
public on<P = any>(type: '**', listener: FastEventListener<Types, P, Meta>): FastEventSubscriber
|
|
114
|
+
public on(): FastEventSubscriber {
|
|
103
115
|
const type = arguments[0] as string
|
|
104
|
-
const listener = arguments[1] as FastEventListener
|
|
116
|
+
const listener = arguments[1] as FastEventListener
|
|
105
117
|
const options = Object.assign({
|
|
106
|
-
count
|
|
118
|
+
count: 0,
|
|
107
119
|
prepend: false
|
|
108
|
-
},arguments[2]) as Required<FastEventListenOptions>
|
|
120
|
+
}, arguments[2]) as Required<FastEventListenOptions>
|
|
109
121
|
|
|
110
|
-
if(type.length===0) throw new Error('event type cannot be empty')
|
|
122
|
+
if (type.length === 0) throw new Error('event type cannot be empty')
|
|
111
123
|
|
|
112
|
-
if(type==='**'){
|
|
124
|
+
if (type === '**') {
|
|
113
125
|
return this.onAny(listener)
|
|
114
126
|
}
|
|
115
127
|
|
|
116
128
|
const parts = type.split(this._delimiter);
|
|
117
|
-
const node = this._addListener(parts,listener,options)
|
|
118
|
-
|
|
129
|
+
const node = this._addListener(parts, listener, options)
|
|
130
|
+
|
|
119
131
|
// Retain不支持通配符
|
|
120
|
-
if(node && !type.includes('*')) this._emitForLastEvent(type)
|
|
132
|
+
if (node && !type.includes('*')) this._emitForLastEvent(type)
|
|
121
133
|
|
|
122
134
|
return {
|
|
123
|
-
off: ()=>node && this._removeListener(node,parts,listener)
|
|
135
|
+
off: () => node && this._removeListener(node, parts, listener)
|
|
124
136
|
}
|
|
125
|
-
}
|
|
137
|
+
}
|
|
126
138
|
|
|
127
|
-
|
|
128
|
-
public once<T extends Types=Types>(type: T, listener: FastEventListener<
|
|
129
|
-
public once(): FastEventSubscriber
|
|
130
|
-
|
|
139
|
+
|
|
140
|
+
public once<T extends Types = Types>(type: T, listener: FastEventListener<T, Events[T], Meta>): FastEventSubscriber
|
|
141
|
+
public once<T extends string>(type: T, listener: FastEventListener<T, Events[T], Meta>): FastEventSubscriber
|
|
142
|
+
public once(): FastEventSubscriber {
|
|
143
|
+
return this.on(arguments[0], arguments[1], { count: 1 })
|
|
131
144
|
}
|
|
132
145
|
|
|
133
146
|
/**
|
|
@@ -144,51 +157,51 @@ export class FastEvent<
|
|
|
144
157
|
* subscriber.off();
|
|
145
158
|
* ```
|
|
146
159
|
*/
|
|
147
|
-
onAny<P=any>(listener: FastEventListener<string,P,Meta>, options?:Pick<FastEventListenOptions,'prepend'>): FastEventSubscriber {
|
|
160
|
+
onAny<P = any>(listener: FastEventListener<string, P, Meta>, options?: Pick<FastEventListenOptions, 'prepend'>): FastEventSubscriber {
|
|
148
161
|
const listeners = this.listeners.__listeners
|
|
149
|
-
if(options && options.prepend){
|
|
150
|
-
listeners.splice(0,0,listener)
|
|
151
|
-
}else{
|
|
162
|
+
if (options && options.prepend) {
|
|
163
|
+
listeners.splice(0, 0, listener)
|
|
164
|
+
} else {
|
|
152
165
|
listeners.push(listener)
|
|
153
|
-
}
|
|
166
|
+
}
|
|
154
167
|
return {
|
|
155
|
-
off:()=>this._removeListener(this.listeners,[],listener)
|
|
168
|
+
off: () => this._removeListener(this.listeners, [], listener)
|
|
156
169
|
}
|
|
157
170
|
}
|
|
158
171
|
|
|
159
|
-
off(listener: FastEventListener<any, any, any>):void
|
|
160
|
-
off(type: string, listener: FastEventListener<any, any, any>):void
|
|
161
|
-
off(type: Types, listener: FastEventListener<any, any, any>):void
|
|
162
|
-
off(type: string):void
|
|
163
|
-
off(type: Types):void
|
|
164
|
-
off(){
|
|
172
|
+
off(listener: FastEventListener<any, any, any>): void
|
|
173
|
+
off(type: string, listener: FastEventListener<any, any, any>): void
|
|
174
|
+
off(type: Types, listener: FastEventListener<any, any, any>): void
|
|
175
|
+
off(type: string): void
|
|
176
|
+
off(type: Types): void
|
|
177
|
+
off() {
|
|
165
178
|
const args = arguments
|
|
166
|
-
const type = typeof(args[0])==='function' ? undefined : args[0]
|
|
167
|
-
const listener = typeof(args[0])==='function' ? args[0] : args[1]
|
|
179
|
+
const type = typeof (args[0]) === 'function' ? undefined : args[0]
|
|
180
|
+
const listener = typeof (args[0]) === 'function' ? args[0] : args[1]
|
|
168
181
|
const parts = type ? type.split(this._delimiter) : []
|
|
169
|
-
const hasWildcard= type ? type.includes('*') : false
|
|
170
|
-
if(type && !hasWildcard){
|
|
171
|
-
this._traverseToPath(this.listeners,parts,(node)=>{
|
|
172
|
-
if(listener){ // 只删除指定的监听器
|
|
173
|
-
this._removeListener(node,parts,listener)
|
|
174
|
-
}else if(type){
|
|
175
|
-
node.__listeners=[]
|
|
182
|
+
const hasWildcard = type ? type.includes('*') : false
|
|
183
|
+
if (type && !hasWildcard) {
|
|
184
|
+
this._traverseToPath(this.listeners, parts, (node) => {
|
|
185
|
+
if (listener) { // 只删除指定的监听器
|
|
186
|
+
this._removeListener(node, parts, listener)
|
|
187
|
+
} else if (type) {
|
|
188
|
+
node.__listeners = []
|
|
176
189
|
}
|
|
177
190
|
})
|
|
178
|
-
}else{ // 仅删除指定的侦听器
|
|
179
|
-
const entryParts:string[] = hasWildcard ? [] : parts
|
|
180
|
-
this._traverseListeners(this.listeners,entryParts,(path,node)=>{
|
|
181
|
-
if(listener!==undefined || (hasWildcard && isPathMatched(path,parts))){
|
|
182
|
-
if(listener){
|
|
183
|
-
this._removeListener(node,parts,listener)
|
|
184
|
-
}else{
|
|
185
|
-
node.__listeners=[]
|
|
186
|
-
}
|
|
191
|
+
} else { // 仅删除指定的侦听器
|
|
192
|
+
const entryParts: string[] = hasWildcard ? [] : parts
|
|
193
|
+
this._traverseListeners(this.listeners, entryParts, (path, node) => {
|
|
194
|
+
if (listener !== undefined || (hasWildcard && isPathMatched(path, parts))) {
|
|
195
|
+
if (listener) {
|
|
196
|
+
this._removeListener(node, parts, listener)
|
|
197
|
+
} else {
|
|
198
|
+
node.__listeners = []
|
|
199
|
+
}
|
|
187
200
|
}
|
|
188
201
|
})
|
|
189
202
|
}
|
|
190
203
|
}
|
|
191
|
-
|
|
204
|
+
|
|
192
205
|
/**
|
|
193
206
|
* 移除所有事件监听器
|
|
194
207
|
* @param entry - 可选的事件前缀,如果提供则只移除指定前缀下的的监听器
|
|
@@ -205,20 +218,21 @@ export class FastEvent<
|
|
|
205
218
|
* emitter.offAll('a/b'); // 清除a/b下的所有监听器
|
|
206
219
|
*
|
|
207
220
|
*/
|
|
208
|
-
offAll(entry?: string) {
|
|
209
|
-
if(entry){
|
|
221
|
+
offAll(entry?: string) {
|
|
222
|
+
if (entry) {
|
|
210
223
|
const entryNode = this._getListenerNode(entry.split(this._delimiter))
|
|
211
|
-
if(entryNode) entryNode.__listeners = []
|
|
224
|
+
if (entryNode) entryNode.__listeners = []
|
|
212
225
|
this._removeRetainedEvents(entry)
|
|
213
|
-
}else{
|
|
214
|
-
this.
|
|
226
|
+
} else {
|
|
227
|
+
this.retainedMessages.clear()
|
|
215
228
|
this.listeners = { __listeners: [] } as unknown as FastListeners
|
|
216
229
|
}
|
|
230
|
+
if (typeof (this._options.onClearListeners) === 'function') this._options.onClearListeners.call(this)
|
|
217
231
|
}
|
|
218
232
|
|
|
219
|
-
private _getListenerNode(parts:string[]):FastListenerNode | undefined{
|
|
233
|
+
private _getListenerNode(parts: string[]): FastListenerNode | undefined {
|
|
220
234
|
let entryNode: FastListenerNode | undefined
|
|
221
|
-
this._forEachNodes(parts,(node)=>{
|
|
235
|
+
this._forEachNodes(parts, (node) => {
|
|
222
236
|
entryNode = node
|
|
223
237
|
})
|
|
224
238
|
return entryNode
|
|
@@ -231,34 +245,37 @@ export class FastEvent<
|
|
|
231
245
|
* @private
|
|
232
246
|
*/
|
|
233
247
|
private _removeRetainedEvents(prefix?: string) {
|
|
234
|
-
if (!prefix) this.
|
|
235
|
-
if(prefix?.endsWith(this._delimiter)){
|
|
236
|
-
prefix+=this._delimiter
|
|
237
|
-
}
|
|
238
|
-
this.
|
|
239
|
-
for(let key of this.
|
|
240
|
-
if(key.startsWith(prefix!)){
|
|
241
|
-
this.
|
|
248
|
+
if (!prefix) this.retainedMessages.clear()
|
|
249
|
+
if (prefix?.endsWith(this._delimiter)) {
|
|
250
|
+
prefix += this._delimiter
|
|
251
|
+
}
|
|
252
|
+
this.retainedMessages.delete(prefix!)
|
|
253
|
+
for (let key of this.retainedMessages.keys()) {
|
|
254
|
+
if (key.startsWith(prefix!)) {
|
|
255
|
+
this.retainedMessages.delete(key)
|
|
242
256
|
}
|
|
243
257
|
}
|
|
244
|
-
}
|
|
245
|
-
clear(){
|
|
258
|
+
}
|
|
259
|
+
clear() {
|
|
246
260
|
this.offAll()
|
|
247
261
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
262
|
+
|
|
263
|
+
private _createMeta(extra: Record<string, any> | undefined) {
|
|
264
|
+
if (!this._options.meta) return extra
|
|
265
|
+
return Object.assign({}, this._options.meta, extra)
|
|
251
266
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
this.
|
|
257
|
-
|
|
258
|
-
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
private _emitForLastEvent(type: string) {
|
|
270
|
+
if (this.retainedMessages.has(type)) {
|
|
271
|
+
const message = this.retainedMessages.get(type)
|
|
272
|
+
const parts = type.split(this._delimiter);
|
|
273
|
+
this._traverseToPath(this.listeners, parts, (node) => {
|
|
274
|
+
this._executeListeners(node, message)
|
|
275
|
+
})
|
|
259
276
|
// onAny侦听器保存在根节点中,所以需要执行
|
|
260
|
-
this._executeListeners(this.listeners,
|
|
261
|
-
}
|
|
277
|
+
this._executeListeners(this.listeners, message)
|
|
278
|
+
}
|
|
262
279
|
}
|
|
263
280
|
|
|
264
281
|
/**
|
|
@@ -275,25 +292,25 @@ export class FastEvent<
|
|
|
275
292
|
* - 单层通配: 'a.*.c'
|
|
276
293
|
* - 多层通配: 'a.**'
|
|
277
294
|
*/
|
|
278
|
-
private _traverseToPath(node: FastListenerNode, parts: string[], callback: (node: FastListenerNode) => void, index: number = 0, lastFollowing?:boolean): void {
|
|
295
|
+
private _traverseToPath(node: FastListenerNode, parts: string[], callback: (node: FastListenerNode) => void, index: number = 0, lastFollowing?: boolean): void {
|
|
279
296
|
|
|
280
297
|
if (index >= parts.length) {
|
|
281
298
|
callback(node)
|
|
282
299
|
return
|
|
283
|
-
}
|
|
284
|
-
const part = parts[index]
|
|
300
|
+
}
|
|
301
|
+
const part = parts[index]
|
|
285
302
|
|
|
286
|
-
if(lastFollowing===true){
|
|
287
|
-
this._traverseToPath(node, parts, callback, index + 1,true)
|
|
303
|
+
if (lastFollowing === true) {
|
|
304
|
+
this._traverseToPath(node, parts, callback, index + 1, true)
|
|
288
305
|
return
|
|
289
306
|
}
|
|
290
307
|
|
|
291
308
|
if ('*' in node) {
|
|
292
309
|
this._traverseToPath(node['*'], parts, callback, index + 1)
|
|
293
|
-
}
|
|
310
|
+
}
|
|
294
311
|
//
|
|
295
312
|
if ('**' in node) {
|
|
296
|
-
this._traverseToPath(node['**'], parts, callback, index + 1,true)
|
|
313
|
+
this._traverseToPath(node['**'], parts, callback, index + 1, true)
|
|
297
314
|
}
|
|
298
315
|
|
|
299
316
|
if (part in node) {
|
|
@@ -301,43 +318,43 @@ export class FastEvent<
|
|
|
301
318
|
}
|
|
302
319
|
}
|
|
303
320
|
|
|
304
|
-
private _traverseListeners(node: FastListenerNode, entry:string[], callback: (path:string[],node: FastListenerNode) => void): void {
|
|
321
|
+
private _traverseListeners(node: FastListenerNode, entry: string[], callback: (path: string[], node: FastListenerNode) => void): void {
|
|
305
322
|
let entryNode: FastListenerNode = node
|
|
306
323
|
// 如果指定了entry路径,则按照路径遍历
|
|
307
|
-
if (entry && entry.length > 0) {
|
|
308
|
-
this._traverseToPath(node, entry,(node)=>{
|
|
309
|
-
entryNode= node
|
|
324
|
+
if (entry && entry.length > 0) {
|
|
325
|
+
this._traverseToPath(node, entry, (node) => {
|
|
326
|
+
entryNode = node
|
|
310
327
|
});
|
|
311
328
|
}
|
|
312
|
-
const traverseNodes = (node: FastListenerNode, callback: (path:string[],node: FastListenerNode) => void,parentPath:string[])=>{
|
|
313
|
-
callback(parentPath, node);
|
|
314
|
-
for(let [key,childNode] of Object.entries(node)){
|
|
315
|
-
if(key.startsWith("__")) continue
|
|
316
|
-
if(childNode){
|
|
317
|
-
traverseNodes(childNode as FastListenerNode, callback,[...parentPath,key]);
|
|
329
|
+
const traverseNodes = (node: FastListenerNode, callback: (path: string[], node: FastListenerNode) => void, parentPath: string[]) => {
|
|
330
|
+
callback(parentPath, node);
|
|
331
|
+
for (let [key, childNode] of Object.entries(node)) {
|
|
332
|
+
if (key.startsWith("__")) continue
|
|
333
|
+
if (childNode) {
|
|
334
|
+
traverseNodes(childNode as FastListenerNode, callback, [...parentPath, key]);
|
|
318
335
|
}
|
|
319
336
|
}
|
|
320
337
|
}
|
|
321
338
|
// 如果没有指定entry或entry为空数组,则递归遍历所有节点
|
|
322
|
-
traverseNodes(entryNode, callback,[]);
|
|
323
|
-
}
|
|
339
|
+
traverseNodes(entryNode, callback, []);
|
|
340
|
+
}
|
|
324
341
|
|
|
325
|
-
private _executeListener(listener:any,
|
|
326
|
-
try{
|
|
327
|
-
if(typeof(listener.__wrappedListener)==='function'){
|
|
328
|
-
return listener.__wrappedListener.call(this._context,
|
|
329
|
-
}else{
|
|
330
|
-
return listener.call(this._context,
|
|
342
|
+
private _executeListener(listener: any, message: FastEventMessage): any {
|
|
343
|
+
try {
|
|
344
|
+
if (typeof (listener.__wrappedListener) === 'function') {
|
|
345
|
+
return listener.__wrappedListener.call(this._context, message)
|
|
346
|
+
} else {
|
|
347
|
+
return listener.call(this._context, message)
|
|
331
348
|
}
|
|
332
|
-
}catch(e:any){
|
|
333
|
-
e.
|
|
334
|
-
if(typeof(this._options.onListenerError)==='function'){
|
|
335
|
-
this._options.onListenerError.call(this,
|
|
349
|
+
} catch (e: any) {
|
|
350
|
+
e._emitter = message.type
|
|
351
|
+
if (typeof (this._options.onListenerError) === 'function') {
|
|
352
|
+
this._options.onListenerError.call(this, message.type, e)
|
|
336
353
|
}
|
|
337
354
|
// 如果忽略错误,则返回错误对象
|
|
338
|
-
if(this._options.ignoreErrors){
|
|
355
|
+
if (this._options.ignoreErrors) {
|
|
339
356
|
return e
|
|
340
|
-
}else{
|
|
357
|
+
} else {
|
|
341
358
|
throw e
|
|
342
359
|
}
|
|
343
360
|
}
|
|
@@ -356,103 +373,137 @@ export class FastEvent<
|
|
|
356
373
|
* - 对于普通监听器,直接执行并收集结果
|
|
357
374
|
* - 对于带次数限制的监听器(数组形式),执行后递减次数,当次数为0时移除该监听器
|
|
358
375
|
*/
|
|
359
|
-
private _executeListeners(node: FastListenerNode,
|
|
376
|
+
private _executeListeners(node: FastListenerNode, message: FastEventMessage): any[] {
|
|
360
377
|
if (!node || !node.__listeners) return []
|
|
361
378
|
let i = 0
|
|
362
379
|
const listeners = node.__listeners
|
|
363
|
-
let result:any[] = []
|
|
364
|
-
while(i<listeners.length){
|
|
380
|
+
let result: any[] = []
|
|
381
|
+
while (i < listeners.length) {
|
|
365
382
|
const listener = listeners[i]
|
|
366
|
-
if(Array.isArray(listener)){
|
|
367
|
-
result.push(this._executeListener(listener[0],
|
|
368
|
-
listener[1]--
|
|
369
|
-
if(listener[1]===0) {
|
|
370
|
-
listeners.splice(i,1)
|
|
383
|
+
if (Array.isArray(listener)) {
|
|
384
|
+
result.push(this._executeListener(listener[0], message))
|
|
385
|
+
listener[1]--
|
|
386
|
+
if (listener[1] === 0) {
|
|
387
|
+
listeners.splice(i, 1)
|
|
371
388
|
i-- // 抵消后面的i++
|
|
372
389
|
}
|
|
373
|
-
}else{
|
|
374
|
-
result.push(this._executeListener(listener,
|
|
375
|
-
}
|
|
376
|
-
i++
|
|
390
|
+
} else {
|
|
391
|
+
result.push(this._executeListener(listener, message))
|
|
392
|
+
}
|
|
393
|
+
i++
|
|
377
394
|
}
|
|
378
395
|
return result
|
|
379
396
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
397
|
+
/**
|
|
398
|
+
* 触发事件并执行对应的监听器
|
|
399
|
+
*
|
|
400
|
+
* @param type - 事件类型字符串或包含事件信息的对象
|
|
401
|
+
* @param payload - 事件携带的数据负载
|
|
402
|
+
* @param retain - 是否保留该事件(用于新订阅者)
|
|
403
|
+
* @param meta - 事件元数据
|
|
404
|
+
* @returns 所有监听器的执行结果数组
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* // 方式1: 参数形式
|
|
408
|
+
* emit('user.login', { id: 1 }, true)
|
|
409
|
+
*
|
|
410
|
+
* // 方式2: 对象形式
|
|
411
|
+
* emit({ type: 'user.login', payload: { id: 1 } ,meta:{...}}}, true)
|
|
412
|
+
*/
|
|
413
|
+
public emit<R = any>(type: string, payload?: any, retain?: boolean, meta?: Meta): R[]
|
|
414
|
+
public emit<R = any>(type: Types, payload?: Events[Types], retain?: boolean, meta?: Meta): R[]
|
|
415
|
+
public emit<R = any>(message: FastEventMessage<Types, Events[Types], Meta>, retain?: boolean): R[]
|
|
416
|
+
public emit<R = any>(message: FastEventMessage<string, any, Meta>, retain?: boolean): R[]
|
|
417
|
+
public emit<R = any>(): R[] {
|
|
418
|
+
let type: string, payload: any, retain: boolean, meta: any
|
|
419
|
+
if (typeof (arguments[0]) === 'object') {
|
|
388
420
|
type = arguments[0].type as string
|
|
389
421
|
payload = arguments[0].payload as any
|
|
390
|
-
meta = (arguments[0]
|
|
391
|
-
retain = arguments[1] as boolean
|
|
392
|
-
}else{
|
|
422
|
+
meta = this._createMeta(arguments[0].meta) as Meta
|
|
423
|
+
retain = arguments[1] as boolean
|
|
424
|
+
} else {
|
|
393
425
|
type = arguments[0] as string
|
|
394
426
|
payload = arguments[1] as any
|
|
395
427
|
retain = arguments[2] as boolean
|
|
396
|
-
meta = (arguments[3]
|
|
397
|
-
}
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
428
|
+
meta = this._createMeta(arguments[3])
|
|
429
|
+
}
|
|
430
|
+
const message: FastEventMessage = {
|
|
431
|
+
type,
|
|
432
|
+
payload,
|
|
433
|
+
meta
|
|
434
|
+
}
|
|
435
|
+
const parts = type.split(this._delimiter);
|
|
436
|
+
if (retain) {
|
|
437
|
+
this.retainedMessages.set(type, message)
|
|
438
|
+
}
|
|
439
|
+
const results: any[] = []
|
|
403
440
|
// onAny侦听器保存在根节点中,所以需要执行
|
|
404
|
-
results.push(...this._executeListeners(this.listeners,
|
|
405
|
-
this._traverseToPath(this.listeners,parts,(node)=>{
|
|
406
|
-
results.push(...this._executeListeners(node,
|
|
407
|
-
|
|
441
|
+
results.push(...this._executeListeners(this.listeners, message))
|
|
442
|
+
this._traverseToPath(this.listeners, parts, (node) => {
|
|
443
|
+
results.push(...this._executeListeners(node, message))
|
|
444
|
+
// 用于调试时使用
|
|
445
|
+
if (this._options.debug && typeof (this._options.onExecuteListener) === 'function') {
|
|
446
|
+
if (retain) {
|
|
447
|
+
if (!message.meta) message.meta = { retain: true }
|
|
448
|
+
}
|
|
449
|
+
this._options.onExecuteListener.call(this, message, results, [...this.listeners.__listeners, ...node.__listeners])
|
|
450
|
+
}
|
|
451
|
+
})
|
|
452
|
+
|
|
408
453
|
return results
|
|
409
454
|
}
|
|
410
455
|
|
|
411
|
-
public async emitAsync<R=any>(type:string,payload?:any,retain?:boolean,meta?:Meta):Promise<[R|Error][]>
|
|
412
|
-
public async emitAsync<R=any>(type:Types,payload?:Events[Types],retain?:boolean,meta?:Meta):Promise<[R|Error][]>
|
|
413
|
-
public async emitAsync<P=any>():Promise<[P|Error][]>{
|
|
456
|
+
public async emitAsync<R = any>(type: string, payload?: any, retain?: boolean, meta?: Meta): Promise<[R | Error][]>
|
|
457
|
+
public async emitAsync<R = any>(type: Types, payload?: Events[Types], retain?: boolean, meta?: Meta): Promise<[R | Error][]>
|
|
458
|
+
public async emitAsync<P = any>(): Promise<[P | Error][]> {
|
|
414
459
|
const type = arguments[0] as string
|
|
415
460
|
const payload = arguments[1] as any
|
|
416
461
|
const retain = arguments[2] as boolean
|
|
417
|
-
const meta = (arguments[3]
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
462
|
+
const meta = this._createMeta((arguments[3])) as Meta
|
|
463
|
+
const message = {
|
|
464
|
+
type,
|
|
465
|
+
payload,
|
|
466
|
+
meta
|
|
467
|
+
}
|
|
468
|
+
const results = await Promise.allSettled(this.emit<P>(message, retain))
|
|
469
|
+
return results.map((result) => {
|
|
470
|
+
if (result.status === 'fulfilled') {
|
|
422
471
|
return result.value
|
|
423
|
-
}else{
|
|
472
|
+
} else {
|
|
424
473
|
return result.reason
|
|
425
474
|
}
|
|
426
475
|
})
|
|
427
476
|
}
|
|
428
477
|
|
|
429
478
|
/**
|
|
430
|
-
* 等待指定事件发生
|
|
479
|
+
* 等待指定事件发生
|
|
480
|
+
*
|
|
481
|
+
* waitFor("x")
|
|
431
482
|
*
|
|
432
483
|
* @param type
|
|
433
484
|
* @param timeout 超时时间,单位毫秒,默认为 0,表示无限等待
|
|
434
485
|
*/
|
|
435
|
-
public waitFor<
|
|
436
|
-
public waitFor<
|
|
437
|
-
public waitFor<
|
|
438
|
-
const type = arguments[0] as
|
|
486
|
+
public waitFor<T extends Types, P = Events[T], M = Meta>(type: T, timeout?: number): Promise<FastEventMessage<T, P, M>>
|
|
487
|
+
public waitFor<T extends string, P = Events[T], M = Meta>(type: string, timeout?: number): Promise<FastEventMessage<T, P, M>>
|
|
488
|
+
public waitFor<T extends string, P = Events[T], M = Meta>(): Promise<FastEventMessage<T, P, M>> {
|
|
489
|
+
const type = arguments[0] as any
|
|
439
490
|
const timeout = arguments[1] as number
|
|
440
|
-
return new Promise<
|
|
441
|
-
let tid:any
|
|
442
|
-
let subscriber:FastEventSubscriber
|
|
443
|
-
const listener = (
|
|
491
|
+
return new Promise<FastEventMessage<T, P, M>>((resolve, reject) => {
|
|
492
|
+
let tid: any
|
|
493
|
+
let subscriber: FastEventSubscriber
|
|
494
|
+
const listener = (message: FastEventMessage<T, P, M>) => {
|
|
444
495
|
clearTimeout(tid)
|
|
445
|
-
subscriber.off()
|
|
446
|
-
resolve(
|
|
496
|
+
subscriber.off()
|
|
497
|
+
resolve(message)
|
|
447
498
|
}
|
|
448
|
-
if(timeout && timeout>0){
|
|
449
|
-
tid = setTimeout(()=>{
|
|
499
|
+
if (timeout && timeout > 0) {
|
|
500
|
+
tid = setTimeout(() => {
|
|
450
501
|
subscriber && subscriber.off()
|
|
451
|
-
reject(new Error('wait for event<'+ type +'> is timeout'))
|
|
452
|
-
},timeout)
|
|
502
|
+
reject(new Error('wait for event<' + type + '> is timeout'))
|
|
503
|
+
}, timeout)
|
|
453
504
|
}
|
|
454
|
-
subscriber = this.on(type,listener)
|
|
455
|
-
})
|
|
505
|
+
subscriber = this.on(type, listener as any)
|
|
506
|
+
})
|
|
456
507
|
}
|
|
457
508
|
|
|
458
509
|
/**
|
|
@@ -473,8 +524,7 @@ export class FastEvent<
|
|
|
473
524
|
* scope.offAll() == emitter.offAll("a/b")
|
|
474
525
|
*
|
|
475
526
|
*/
|
|
476
|
-
scope<T extends string>(prefix:T){
|
|
477
|
-
return new FastEventScope<ScopeEvents<Events,T>>(this as unknown as FastEvent<ScopeEvents<Events,T>>,prefix)
|
|
527
|
+
scope<T extends string>(prefix: T) {
|
|
528
|
+
return new FastEventScope<ScopeEvents<Events, T>>(this as unknown as FastEvent<ScopeEvents<Events, T>>, prefix)
|
|
478
529
|
}
|
|
479
|
-
|
|
480
530
|
}
|