Skip to content

Commit

Permalink
Implement AsyncEventEmitter
Browse files Browse the repository at this point in the history
Co-Authored-By: Denys Otrishko <shishugi@gmail.com>
Co-Authored-By: Mykola Bilochub <nbelochub@gmail.com>
Co-Authored-By: Dmytro Nechai <nechaido@gmail.com>
  • Loading branch information
4 people committed Jun 9, 2019
1 parent 29a04ba commit e616109
Show file tree
Hide file tree
Showing 5 changed files with 443 additions and 0 deletions.
1 change: 1 addition & 0 deletions .metadocrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"files": [
"lib/adapters.js",
"lib/array.js",
"lib/async-emitter.js",
"lib/async-iterator.js",
"lib/chain.js",
"lib/collector.js",
Expand Down
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,78 @@ Asynchronous some (iterate in series)

Non-blocking synchronous map

### class AsyncEmitter

#### AsyncEmitter.prototype.constructor()

#### AsyncEmitter.prototype.event(name)

- `name`: [`<string>`][string] event name

_Returns:_ { on: [`<Set>`][set], once: [`<Set>`][set] } }

Get or create event

#### AsyncEmitter.prototype.on(name, fn)

- `name`: [`<string>`][string] event name
- `fn`: [`<Function>`][function] listener

Add listener

#### AsyncEmitter.prototype.once(name, fn)

- `name`: [`<string>`][string] event name
- `fn`: [`<Function>`][function] listener

_Returns:_ [`<Promise>`][promise]|[`<null>`][null]

Add listener

#### AsyncEmitter.prototype.emit(name, args)

- `name`: [`<string>`][string] event name
- `args`: `<any[]>`

_Returns:_ [`<Promise>`][promise]|[`<null>`][null]

Emit event

#### AsyncEmitter.prototype.remove(name, fn)

- `name`: [`<string>`][string] event name
- `fn`: [`<Function>`][function] listener to remove

Remove event listener

#### AsyncEmitter.prototype.clear(name)

- `name`: [`<string>`][string] event name

Remove all listeners or by name

#### AsyncEmitter.prototype.count(name)

- `name`: [`<string>`][string] event name

_Returns:_ [`<number>`][number]

Get listeners count by event name

#### AsyncEmitter.prototype.listeners(name)

- `name`: [`<string>`][string] event name

_Returns:_ [`<Function[]>`][function]

Get listeners array by event name

#### AsyncEmitter.prototype.names()

_Returns:_ [`<string[]>`][string] names

Get event names array

### asyncIter(base)

- `base`: [`<Iterable>`][iterable]|[`<AsyncIterable>`][asynciterable] an
Expand Down Expand Up @@ -921,6 +993,7 @@ Set timeout for asynchronous function execution
[object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
[function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
[promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
[set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
[array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
[error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
[boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type
Expand Down
106 changes: 106 additions & 0 deletions lib/async-emitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
'use strict';

class AsyncEmitter {
constructor() {
this.events = new Map();
}

// Get or create event
// name <string> event name
// Returns: { on: <Set>, once: <Set> } }
event(name) {
const { events } = this;
const event = events.get(name);
if (event) return event;
const res = { on: new Set(), once: new Set() };
events.set(name, res);
return res;
}

// Add listener
// name <string> event name
// fn <Function> listener
on(name, fn) {
this.event(name).on.add(fn);
}

// Add listener
// name <string> event name
// fn <Function> listener
// Returns: <Promise> | <null>
once(name, fn) {
if (fn === undefined) {
return new Promise(resolve => {
this.once(name, resolve);
});
}
this.event(name).once.add(fn);
return null;
}

// Emit event
// name <string> event name
// args <any[]>
// Returns: <Promise> | <null>
emit(name, ...args) {
const { events } = this;
const event = events.get(name);
if (!event) return null;
const { on, once } = event;
const promises = [...on.values(), ...once.values()].map(fn => fn(...args));
once.clear();
if (on.size === 0) events.delete(name);
return Promise.all(promises);
}

// Remove event listener
// name <string> event name
// fn <Function> listener to remove
remove(name, fn) {
const { events } = this;
const event = events.get(name);
if (!event) return;
const { on, once } = event;
on.delete(fn);
once.delete(fn);
if (on.size === 0 && once.size === 0) {
events.delete(name);
}
}

// Remove all listeners or by name
// name <string> event name
clear(name) {
const { events } = this;
if (!name) events.clear();
else events.delete(name);
}

// Get listeners count by event name
// name <string> event name
// Returns: <number>
count(name) {
const event = this.events.get(name);
if (!event) return 0;
const { on, once } = event;
return on.size + once.size;
}

// Get listeners array by event name
// name <string> event name
// Returns: <Function[]>
listeners(name) {
const event = this.events.get(name);
if (!event) return [];
const { on, once } = event;
return [...on.values(), ...once.values()];
}

// Get event names array
// Returns: <string[]> names
names() {
return [...this.events.keys()];
}
}

module.exports = { AsyncEmitter };
1 change: 1 addition & 0 deletions metasync.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const submodules = [
'composition', // Unified abstraction
'adapters', // Adapters to convert different async contracts
'array', // Array utilities
'async-emitter', // AsyncEmitter
'chain', // Process arrays sync and async array in chain
'collector', // DataCollector and KeyCollector
'control', // Control flow utilities
Expand Down

0 comments on commit e616109

Please sign in to comment.