Powerful event-based system that introduces thenable objects to enable promise-like event handling
- Improved compatibility with
thenable
definition in Promises/A+ spec - Introduction of Namespaced events
- Contributors: Introduction of proper
mocha
andchai
tests
- Dispatch events
- Handle success and error events using promise-like syntax
- Implements
thenables
compatible with Promises/A+ spec - Namespaced events work out of the box
Install:
$ yarn add thenable-events
Use:
import Dispatcher from 'thenable-events';
const EventDispatcher = new Dispatcher();
EventDispatcher.when('eventName').then(val => console.log(val));
EventDispatcher.resolve('eventName', 'Foobar!');
// Console> 'Foobar!'
Traditional event-based systems combine the antiquated callback
structure in order to handle events:
myObservable.on('eventName', () => console.log('Foobar!'));
While thenable-events
employs a promise-like structure that is compatible with Promises/A+ implementations:
import Dispatcher from 'thenable-events';
const EventDispatcher = new Dispatcher();
EventDispatcher.when('eventName').then(() => console.log('Foobar!'));
Because of these improvements, we can use the power of chaining in a promise-like structure with event-based syntax where the chain is resolved every time an event is fired.
Here's an example using axios
for an API call:
import axios from 'axios';
import Dispatcher from 'thenable-events';
const EventDispatcher = new Dispatcher();
const getData = () =>
axios.get('/svcs/myendpoint').then(
(res) => {
EventDispatcher.resolve('api.myendpoint', res.body);
return res;
},
(err) => {
EventDispatcher.reject('api.myendpoint', err);
throw err;
}
);
// ...
EventDispatcher.when('api.myendpoint')
.then(body => JSON.parse(body))
.then(json => console.log({ json }))
.catch(err => console.error(err));
Support for namespaced event-names works out of the box, enabling handling of a wide-range of events within a single line:
const getData = () =>
// ...
EventDispatcher.reject('api.myendpoint', err);
// ...
// Catches all rejected events under 'api.myendpoint.*'
EventDispatcher.when('api.*')
.catch(err => {
console.error('Catch-all for All API Errors', err);
});
With the promises becoming more ubiquitous due to their powerful structure, thenable-events
employs thenable
objects (as defined in Promises/A+) with interfaces very similar to Promises.
The power of thenable-events
is the similarity in the way that the then
interface is implemented. The interface is entirely compatible with traditional Promise/A+ implementations. However, the real power comes from the ability to use promise-like syntax (thenable) within an event-based structure.
So what are the true differences?
It's quite simple, really:
thenable-events
resolves eachthen
chain every time an event isresolved
orrejected
This is the only limitation with Promises being assimilated in a proper event-based architecture without the need for callbacks.
This issue is solved with thenable-events
:
Old
myObservable.on('api.myendpoint', (data) => {
let json;
try {
json = JSON.parse(data);
} catch(e) {
console.error(err);
return;
}
console.log({ json });
});
New
EventDispatcher.when('api.myendpoint')
.then(body => JSON.parse(body))
.then(json => console.log({ json }))
.catch(err => console.error(err));
Dispatcher
.when()
✓ should throw an error if there are too many parameters
✓ should be compatible with Promise.all
✓ should be compatible with Promise.race
.then( onFulfilled, onRejected )
✓ should execute `onFulfilled` once if already resolved and once for every subsequent resolve
✓ should execute `onRejected` once if thenable is already rejected and once for every subsequent reject
✓ should accept other promises as return values for `thens`
✓ should return properly chainable `thenables`
✓ should throw an error if there are missing parameters
.catch()
✓ should catch when a thenable is rejected within a then
✓ should only fulfill catches
.once( onFulfilled )
✓ should only fulfill once
✓ should fulfill when thenable is already resolved
✓ should fulfill when a thenable is resolved later
✓ should throw an error if there are missing parameters
.catch()
✓ should catch when a thenable is already rejected
✓ should recover if catch returns a value
✓ should only fulfill catches
✓ should throw an error if there are missing parameters
.resolve
✓ should resolve all 3 thens including those in lower namespaces, excluding those in higher namespaces
✓ should not resolve absolute thens in lower namespaces
.reject
✓ should reject all 3 catchs including those in lower namespaces, excluding those in higher namespaces
✓ should not reject absolute catchs in lower namespaces