Skip to content

Commit 77f6330

Browse files
tshemsedinovlundibundibelochubnechaido
committed
Implement AsyncEventEmitter
Co-Authored-By: Denys Otrishko <[email protected]> Co-Authored-By: Mykola Bilochub <[email protected]> Co-Authored-By: Dmytro Nechai <[email protected]>
1 parent 29a04ba commit 77f6330

File tree

5 files changed

+412
-0
lines changed

5 files changed

+412
-0
lines changed

.metadocrc

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"files": [
77
"lib/adapters.js",
88
"lib/array.js",
9+
"lib/async-emitter.js",
910
"lib/async-iterator.js",
1011
"lib/chain.js",
1112
"lib/collector.js",

README.md

+65
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,70 @@ Asynchronous some (iterate in series)
301301

302302
Non-blocking synchronous map
303303

304+
### class AsyncEmitter
305+
306+
#### AsyncEmitter.prototype.constructor()
307+
308+
#### AsyncEmitter.prototype.on(name, fn)
309+
310+
- `name`: [`<string>`][string] event name
311+
- `fn`: [`<Function>`][function] listener
312+
313+
Add listener
314+
315+
#### AsyncEmitter.prototype.once(name, fn)
316+
317+
- `name`: [`<string>`][string] event name
318+
- `fn`: [`<Function>`][function] listener
319+
320+
_Returns:_ [`<Promise>`][promise]|[`<undefined>`][undefined]
321+
322+
Add listener
323+
324+
#### async AsyncEmitter.prototype.emit(name, args)
325+
326+
- `name`: [`<string>`][string] event name
327+
- `args`: `<any[]>`
328+
329+
_Returns:_ [`<Promise>`][promise]|[`<undefined>`][undefined]
330+
331+
Emit event
332+
333+
#### AsyncEmitter.prototype.remove(name, fn)
334+
335+
- `name`: [`<string>`][string] event name
336+
- `fn`: [`<Function>`][function] listener to remove
337+
338+
Remove event listener
339+
340+
#### AsyncEmitter.prototype.clear(name)
341+
342+
- `name`: [`<string>`][string] event name
343+
344+
Remove all listeners or by name
345+
346+
#### AsyncEmitter.prototype.count(name)
347+
348+
- `name`: [`<string>`][string] event name
349+
350+
_Returns:_ [`<number>`][number]
351+
352+
Get listeners count by event name
353+
354+
#### AsyncEmitter.prototype.listeners(name)
355+
356+
- `name`: [`<string>`][string] event name
357+
358+
_Returns:_ [`<Function[]>`][function]
359+
360+
Get listeners array by event name
361+
362+
#### AsyncEmitter.prototype.names()
363+
364+
_Returns:_ [`<string[]>`][string] names
365+
366+
Get events name array
367+
304368
### asyncIter(base)
305369

306370
- `base`: [`<Iterable>`][iterable]|[`<AsyncIterable>`][asynciterable] an
@@ -925,6 +989,7 @@ Set timeout for asynchronous function execution
925989
[error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
926990
[boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type
927991
[null]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Null_type
992+
[undefined]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type
928993
[number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type
929994
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type
930995
[iterable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols

lib/async-emitter.js

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
'use strict';
2+
3+
const { iter } = require('@metarhia/common');
4+
5+
class AsyncEmitter {
6+
constructor() {
7+
this.events = new Map();
8+
this.wrappers = new Map();
9+
}
10+
11+
// Add listener
12+
// name <string> event name
13+
// fn <Function> listener
14+
on(name, fn) {
15+
let event = this.events.get(name);
16+
if (!event) {
17+
event = new Set();
18+
this.events.set(name, event);
19+
}
20+
event.add(fn);
21+
}
22+
23+
// Add listener
24+
// name <string> event name
25+
// fn <Function> listener
26+
// Returns: <Promise> | <undefined>
27+
once(name, fn) {
28+
if (fn === undefined) {
29+
return new Promise(resolve => {
30+
this.once(name, resolve);
31+
});
32+
}
33+
const wrapper = (...args) => {
34+
this.remove(name, fn);
35+
return fn(...args);
36+
};
37+
this.wrappers.set(fn, wrapper);
38+
this.on(name, wrapper);
39+
return undefined;
40+
}
41+
42+
// Emit event
43+
// name <string> event name
44+
// args <any[]>
45+
// Returns: <Promise> | <undefined>
46+
async emit(name, ...args) {
47+
const event = this.events.get(name);
48+
if (!event) return undefined;
49+
const listeners = event.values();
50+
const promises = iter(listeners).map(fn => fn(...args));
51+
return Promise.all(promises);
52+
}
53+
54+
// Remove event listener
55+
// name <string> event name
56+
// fn <Function> listener to remove
57+
remove(name, fn) {
58+
const { events, wrappers } = this;
59+
const event = events.get(name);
60+
if (!event) return;
61+
if (event.has(fn)) event.delete(fn);
62+
const wrapper = wrappers.get(fn);
63+
if (wrapper) {
64+
wrappers.delete(fn);
65+
event.delete(wrapper);
66+
}
67+
if (event.size === 0) events.delete(name);
68+
}
69+
70+
// Remove all listeners or by name
71+
// name <string> event name
72+
clear(name) {
73+
const { events, wrappers } = this;
74+
if (!name) {
75+
events.clear();
76+
wrappers.clear();
77+
return;
78+
}
79+
const event = events.get(name);
80+
if (!event) return;
81+
for (const [fn, wrapper] of wrappers.entries()) {
82+
if (event.has(wrapper)) wrappers.delete(fn);
83+
}
84+
events.delete(name);
85+
}
86+
87+
// Get listeners count by event name
88+
// name <string> event name
89+
// Returns: <number>
90+
count(name) {
91+
const event = this.events.get(name);
92+
return event ? event.size : 0;
93+
}
94+
95+
// Get listeners array by event name
96+
// name <string> event name
97+
// Returns: <Function[]>
98+
listeners(name) {
99+
const event = this.events.get(name);
100+
return [...event];
101+
}
102+
103+
// Get event names array
104+
// Returns: <string[]> names
105+
names() {
106+
return [...this.events.keys()];
107+
}
108+
}
109+
110+
module.exports = { AsyncEmitter };

metasync.js

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const submodules = [
77
'composition', // Unified abstraction
88
'adapters', // Adapters to convert different async contracts
99
'array', // Array utilities
10+
'async-emitter', // AsyncEmitter
1011
'chain', // Process arrays sync and async array in chain
1112
'collector', // DataCollector and KeyCollector
1213
'control', // Control flow utilities

0 commit comments

Comments
 (0)