A minimalistic RFP library for event-driven architectures
npm install eventbus.jsA minimalistic RFP library for event-driven architectures.
> _There comes a time in all good programs when components or subsystems must stop
> communicating directly with one another. This is often achieved via the introduction
> of queues between the producers of data and the consumers/processors of that data. This
> architectural indirection ensures that important decisions can be made with some degree of
> independence, and leads to systems that are easier to understand, manage, monitor and change,
> and make better use of computational resources, etc._
> — Rich Hickey
That time came for one of my side projects. I could use some of the available
alternatives, but I do side projects not for the sake of productivity, but to keep my saw sharp.
So I decided to reinvent the wheel.
The main difference to the existing alternatives, is that the EventBus is intended to be a central component
of a conglomerate of heterogeneous units, s.t. other components are wrapped around it.
Whereas the majority of the existing solutions rather work with lots of streams, which are derived from any possible
source of event sequences.
An _event bus_ is a simple medium for message exchange among independent components.
It understands two primitives: _events_ and _event handlers_.
Events have a _type_ and a _payload_.
Event handlers are registered per _event type_.
That is, a handler registered for events of type X will "see" all events of type X emitted to the event bus,
but no events of different types.
An exception is the type "*", which mean "all events" (see below).
The event bus should be considered as a non-deterministic untimed medium.
Hence, no assumptions are allowed about:
- the handler execution order for an emitted event;
- the absolute timing of the event processing.
An event bus can be forked (branched).
Every child inherits those events of its parent, whose types were specified during branching.
The branching can be used to implicitly implement logical transactions:
a component which emits and consumes its own events should always use a separate event bus if possible.
In the following example, we create an event bus and subscribe two listeners to it.
``javascript`
var inputs = new EventBus();
inputs.subscribe("NUMBER", function(type, payload) {
console.log("number", payload, "was emitted to the event bus");
});
inputs.subscribe("CHARACTER", function(type, payload) {
console.log("character", payload, "was emitted to the event bus");
});
As next, we put some events onto the even bus.
`javascript`
inputs.put("NUMBER", 5);
inputs.put("CHARACTER", "c");
As expected, it results in two console messages:
number 5 was emitted to the event bus
character c was emitted to the event bus
Lets derive a child instance:
`javascript`
var numbers = inputs.branch(["NUMBER"]);
That is, we derive from the inputs bus a new bus specifying all event types, which will be forwarded to the newNUMBER
branch. In this case, it's only the event type .
Now we put a listener on the new bus.
`javascript`
numbers.subscribe("*", function(type, payload){
var square = payload * payload;
console.log("square number", square, "was computed.");
});
Now we put two events t the original bus.
`javascript`
inputs.put("NUMBER", 7);
inputs.put("CHARACTER", "d");
The output should be:
number 7 was emitted to the event bus
square number 49 was computed.
character d was emitted to the event bus
Since only the NUMBER event was propagated to the branched bus, we square the emitted number.
Putting a number to the branched bus will not affect the parent:
`javascript`
numbers.put("NUMBER", 8);
results in:
square number 64 was computed.
#### Event
An event consists of a type and of a payload intended for the corresponding event handler.
The payload can be any valid JavaScript value.
For example, this is a valid bus event:
{
type: "someId",
payload: { a: 2, b: 3}
}
#### Event Handler
An event handler receives as argument the event type, the payload and the reference of the event bus instance,
on which the handler is registered.
This reference can be used by the handler to emit further events.
The only output accepted by the event handler is a boolean value indicating its execution status
(true is successful, any other value is considered as failed execution).
This status is used by the Event Bus in case if the handler was configured to fire a bounded number of times.
This is a valid event handler (which, doesn't handle anything, obviously):
function(eventType, payload) {
return true
}
There is a _special_ type event "*" which means "all events"."*"
All handlers subscribed to the type event will receive all events sent to this bus.
#### Instantiation
var bus = new EventBus()
#### Emitting Events
bus.put({type: "someString", payload: someObject})
or more conveniently, just
bus.put(someString, someObject)
Where:
- eventType is the type of the emitted event;payload
- can be any JavaScript value.
#### Event Handler Registration
bus.subscribe(eventType, handlerFunction, expirationCounter)
Where:
- eventType is the type of events, which will be trigger the event handler;handlerFunction
- is the actual handler of type described above;expirationCounter
- is a number defining how often the handler will be fired, before it expires:false
if no value specified, the handler will never expire. The expiration can be controlled by the handler itself:
a call is only counted if the result of the call is not equal to (i.e., undefined counts as a successful
call).
#### Branching
var childBus = bus.branch()
var childBus2 = bus.branch(["Type1", "Type2"])
Thi first child will receive all parent's events, whereas the second on will receive only events of the specified
types. All events put to the child are invisible for the parent.
bus.close()
Closes the bus. A closed bus deletes all of its event handlers and does not react on event emitting anymore.
A closed child also notifies its parent about closing, which makes the parent deleting the child reference.
#### Merging
var mergedBus = bus.merge(anotherBus)
merges two bus instances into a new bus, which will receive events of both bus instances.
The merged bus instance is considered as a child of the instance, on which you call the merge` method.
Distributed under ISC license.