Skip to content

Commit

Permalink
Implement AsyncEventEmitter
Browse files Browse the repository at this point in the history
Co-Authored-By: Denys Otrishko <[email protected]>
Co-Authored-By: Mykola Bilochub <[email protected]>
Co-Authored-By: Dmytro Nechai <[email protected]>
  • Loading branch information
4 people committed Jun 7, 2019
1 parent 29a04ba commit 7d637fa
Show file tree
Hide file tree
Showing 5 changed files with 452 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
74 changes: 74 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,79 @@ Asynchronous some (iterate in series)

Non-blocking synchronous map

### class AsyncEmitter

#### AsyncEmitter.prototype.constructor()

#### 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

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

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

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

Emit event

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

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

_Returns:_ { on [`<Function>`][function], once [`<Function>`][function] }

Get or create event

#### 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

#### 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]|[`<undefined>`][undefined]

Add listener

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

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

Remove event listener

### asyncIter(base)

- `base`: [`<Iterable>`][iterable]|[`<AsyncIterable>`][asynciterable] an
Expand Down Expand Up @@ -925,6 +998,7 @@ Set timeout for asynchronous function execution
[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
[null]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Null_type
[undefined]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type
[number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type
[iterable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
Expand Down
114 changes: 114 additions & 0 deletions lib/async-emitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
'use strict';

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

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

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

// Add listener
// name <string> event name
// fn <Function> listener
// Returns: <Promise> | <undefined>
once(name, fn) {
if (fn === undefined) {
return new Promise(resolve => {
this.once(name, resolve);
});
}
const wrapper = (...args) => {
this.remove(name, fn, true);
return fn(...args);
};
const { once } = this.event(name);
once.set(fn, wrapper);
return undefined;
}

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

// Remove event listener
// name <string> event name
// fn <Function> listener to remove
// onceOnly <boolean> remove once only
remove(name, fn, onceOnly = false) {
const { events } = this;
const event = events.get(name);
if (!event) return;
const { on, once } = event;
if (!onceOnly) 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();
return;
}
const event = events.get(name);
if (event) 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.keys()];
}

// 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
Loading

0 comments on commit 7d637fa

Please sign in to comment.