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