This was a simple pub sub system I wrote based on some code I saw in the past.
This came from a time where jQuery was the popular library to solve website building problems for frontend.
This was written before ES6 so we didn’t have let and const yet. I wrote it to be a Revealing Module Pattern In JavaScript.
var emitter = (function () {
"use strict"
//VARS
var _name = "Emitter"
var ledger = {} // Stores the subscribed callbacks to be triggered on event emit.
//GETTERS
// Return a view of the ledger / mostly for fun
function viewLedger() {
var l = ledger
return l
}
// FUNCTIONS
// subscribe to an event
function subscribe(eventName, fn) {
console.debug("%s [ subscribe ] : ( %s )", _name, eventName)
// Creates an empty array on the ledger object if one doesn't exist already
ledger[eventName] = ledger[eventName] || []
// Add the function to be called when this event is emitted
ledger[eventName].push(fn)
}
// unsubscribe an event
function unsubscribe(eventName, fn) {
console.debug("%s [ unsubscribe ] : ( %s )", _name, eventName)
if (ledger[eventName]) {
for (var i = 0; i < ledger[eventName].length; i++) {
if (ledger[eventName][i] === fn) {
ledger[eventName].splice(i, 1)
break
}
}
}
}
// Emit event(s)
function emit(eventName, data) {
console.debug("%s [ emit ] : ( %s )", _name, eventName)
if (ledger[eventName]) {
console.debug("\tFound( %s ) %s to emit.", ledger[eventName].length, eventName)
ledger[eventName].forEach(function (fn) {
fn(data) // call the fn of each "subscribed" event
console.debug("\t\t callback ran:", fn.toString().split(" ")[1])
})
} else {
console.debug("\t No Subscribers")
}
}
//EXPOSE
return {
ViewLedger: viewLedger,
Subscribe: subscribe,
Unsubscribe: unsubscribe,
Emit: emit,
}
})()Modern version?
Testing out a modernized version of the script
class Emitter {
#name = "Emitter"
#ledger = new Map()
viewLedger() {
return Object.fromEntries(this.#ledger)
}
subscribe(eventName, fn) {
console.debug(`${this.#name} [ subscribe ] : ( ${eventName} )`)
if (!this.#ledger.has(eventName)) this.#ledger.set(eventName, [])
this.#ledger.get(eventName).push(fn)
}
unsubscribe(eventName, fn) {
console.debug(`${this.#name} [ unsubscribe ] : ( ${eventName} )`)
const events = this.#ledger.get(eventName)
if (!events) return
this.#ledger.set(
eventName,
events.filter((cb) => cb !== fn),
)
}
emit(eventName, data) {
console.debug(`${this.#name} [ emit ] : ( ${eventName} )`)
const events = this.#ledger.get(eventName)
if (!events?.length) {
console.debug("\tNo Subscribers")
return
}
console.debug(`\tFound( ${events.length} ) ${eventName} to emit.`)
events.forEach((fn) => {
fn(data)
console.debug(`\t\tcallback ran: ${fn.name || "<anonymous>"}`)
})
}
}
// usage
const emitter = new Emitter()
emitter.subscribe("test", (msg) => console.log("received:", msg))
emitter.emit("test", "hello world")