Huy's Notes
Implementing an Event System

Implementing an Event System

Event System is a mechanism to globally receiving and broadcasting messages, which can be used in a Web Application to allow different components that does not have any parent-child relation, to communicate with each other.

Technical Background

  • There's a native Event support in the browser. It works on element level. We gonna stick with the top level element, the document.
  • To listen to an event, use document.addEventListener(<event-name>, <callback>), where callback is a function that takes an Event object as its only parameter.
  • To create an event with some additional data, use CustomEvent, any data that being passed into the constructor will be available via detail object.
    const event = new CustomEvent("event-name", {  
        a: 10,  
        b: 'Hello'  
    });  
    
  • To dispatch the event, do it in document level document.dispatchEvent(evt).
  • With this approach, we could not clean up the event listeners after the class instance being destroyed, because there's no way we can detect whenever the class being destroyed. We can still provide a way to let user deallocate it themself.
  • So, instead of using document, we can create a new dummy target, using this, we don't have to worry about cleaning up things after the class being destroyed, because the target itself, will be destroyed too.
    const target = new EventTarget();  
    target.dispatchEvent(evt);  
    
  • Using browser's Event API, we can have the benefit of using e.preventDefault() (to cancel an event, if that event has cancellable set to true), e.stopPropagation().
  • The down side probably be the dependency on the DOM API, which make this only work with the browsers, but that's the intention.

API Desgin

  • Init the Event System:
    const comm = new EventSystem();  
    
    If there are different EventSystem's instance, each of them should be able to track their own events, with no overlap, even if the event names are the same.
  • Dispatch an Event:
    comm.emit("event-name", {  
        customData: 'Hello'  
    });  
    
  • Handling an Event:
    comm.on("event-name", (event) => {  
        console.log(event);  
    });  
    
  • Optional but nice to have, it should supports once(), off() methods.

Implementation Notes

  • This would be a class, where each event system instance can be created with a dummy DOM element to handle the creation and dispatch of an event. This can help avoid overlapping event between multiple instances of the class as well.
    class EventSystem {  
        constructor() {  
            this.target = new EventTarget();  
        }  
    }  
    
  • Dispatching an event should take the event system instance into its account, and the new event is based on CustomEvent:
    class EventSystem {  
        ...  
        emit(name: string, detail: any) {  
            const e = new CustomEvent(name, { detail, cancellable: true });  
            this.target.dispatchEvent(e);  
        }  
        ...  
    }  
    
  • Then, event handling is just simple, but we're messing with document, it's neccessary to keep track of the event listeners, and remove them upon the instance destroy.
    class EventSystem {  
        ...  
        on(name: string, fn: EventHandler) {  
            this.target.addEventListener(name, fn);  
        }  
        ...  
    }  
    

Referred in


If you think this note resonated, be it positive or negative, please feel free to send me an email and we can talk.