The addition of custom event types and event buffering
In the first part we have gone through the creation of the initial Event System. It allowed tracking events happening anywhere in the code and trigger handlers for these events.
Anyway, the events currently must be predefined in the source code of the Event System. Also, there is no event buffering, which means some code that has to process older events would not be able to retrieve them.
Due to the impossibility to pass and store types to the Event System made using the Singleton pattern, it is necessary to remove this pattern. So this post expects working with code without a private constructor,
getInstance method and
instance field of the Event System class.
After implementing this part, the Event System should always be initialized and stored in the code as a separate module.
The current implementation allows to set predefined list of events that can be tracked via the Events System. Using such an implementation as a library will not allow third-party developers to extend this list according to their own needs. Also, such a lack makes code hard to refactor.
To fix this issue we can use the power of TypeScript with generics, which will make third-party customization easier.
Types and Interfaces Refactoring
Firstly, it is necessary to update type definitions including Event System class types.
The event system is expected to work with object-like types, in which the key is the name of the event and the value is a function that will be triggered when the event happens. So we can refactor our types to accept this kind of variable using TypeScript generics.
Using this refactoring makes it possible to pass a type containing key-value pairs of events’ names and their handlers. Such refactoring will be useful while adding generics to the Event System class methods.
Class Methods Refactoring
To make Event System class methods work with events type passed via constructor, it is necessary to pass a type containing event’s names that will be handled.
After this update it will be possible to present the event name via generic while calling the function. Anyway, passing event name via generic is not necessary, because it is also passed as a function parameter, so it will be bound to generic key and this will ensure type safety while passing handler function or its parameters.
Events buffering can be useful when some of the Subscribers attach to an event too late when the event has already been triggered. This missed event trigger may be important for the Subscriber, but in the current implementation, it is unable to get it afterward.
Events buffering implementation will store the few last events. If the subscriber will attach later, he will receive the last few events and will have the possibility to handle them.
To implement this feature is necessary to install third-party lib Mnemonist, which has the functionality of fixed-length buffers. The last item is deleted when there is a new item in such kind of buffer. This is useful to prevent storing all events, which can potentially fill a lot of memory even if they will not be needed anymore.
The Event System should have availability to configure buffer behavior. For this purpose, it is reasonable to introduce a few more types. The current buffer implementation assumes setting buffer direction from the following (First-In-First-Out or Last-In-First-Out) and buffers size.
Event System Class Buffer Introduce
To set up buffer configuration it is required to pass buffer setup options via Event System constructor parameters. These parameters should be also made optional, so the Event System can be easier used as a library by third party developers.
The Mneonist data structure called
CircularBuffer will be used to store a particular number of the last events. It will make sure that the number of events stored in the array is always constant.
Buffer Processing Logic
To store past events and trigger their handlers from new subscribers, it is necessary to update Event System methods.
subscribe method should check if there are any events in the buffer, in which a new subscriber is interested.
notify method should store all the events it receives in the buffer, to make their processing available for the subscribe method.
Currently implemented logic makes it possible to initialize the Event System in a separate module and use it anywhere in the code. TypeScript with generics provides availability to set custom event types and ensures event handlers and arguments are passed with required data types. Events buffering affords events to be buffered and available for late subscribers.
Github Repository: https://github.com/NickSettler/events-system