Skip to content

Commit 885ef81

Browse files
tshemsedinovlundibundibelochubnechaido
committed
Implement AsyncEventEmitter
Co-Authored-By: Denys Otrishko <shishugi@gmail.com> Co-Authored-By: Mykola Bilochub <nbelochub@gmail.com> Co-Authored-By: Dmytro Nechai <nechaido@gmail.com>
1 parent 85509e9 commit 885ef81

File tree

5 files changed

+443
-0
lines changed

5 files changed

+443
-0
lines changed

.metadocrc

Lines changed: 1 addition & 0 deletions
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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,78 @@ Asynchronous some (iterate in series)
301301

302302
Non-blocking synchronous map
303303

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

306378
- `base`: [`<Iterable>`][iterable]|[`<AsyncIterable>`][asynciterable] an
@@ -921,6 +993,7 @@ Set timeout for asynchronous function execution
921993
[object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
922994
[function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
923995
[promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
996+
[set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
924997
[array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
925998
[error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
926999
[boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type

lib/async-emitter.js

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

metasync.js

Lines changed: 1 addition & 0 deletions
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)