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