Skip to content

Instantly share code, notes, and snippets.

@nathnolt
Last active April 7, 2026 21:24
Show Gist options
  • Select an option

  • Save nathnolt/260fccc5f9f2aed143336b68c7f07714 to your computer and use it in GitHub Desktop.

Select an option

Save nathnolt/260fccc5f9f2aed143336b68c7f07714 to your computer and use it in GitHub Desktop.
small 325 bytes JS event system with array support and priority via unshift
/**
* An event system which allows arrays of events and handlers within the method calls.
*/
export function eventSystem() {
// all as let for compacting
let map = {}
let getFlattenedArray = (x) => [x].flat(Infinity)
// For futher compacting
let arr
let event
let handler
let index
/**
* @typedef { ({type: string, data: unknown}) => void } handler
*/
return {
/**
* Listen to events
* @param {string|string[]} events - Which event(s) to listen to
* @param {handler|handler[]} handlers - What handlers handle these events
* @param {boolean} unshift - When truthy: Execute these handlers first
*/
on(events, handlers, unshift) {
for(event of getFlattenedArray(events)) {
arr = map[event] ??= []
for(handler of getFlattenedArray(handlers)) {
if(arr.indexOf(handler) == -1) {
if(unshift) {
arr.unshift(handler)
} else {
arr.push(handler)
}
}
}
}
},
/**
* Emit events to listeners
* @param {string|string[]} events - What event(s) to emit
* @param {unknown} data - What data to add
*/
emit(events, data) {
for(event of getFlattenedArray(events)) {
for(handler of map[event] ?? []) {
handler({type: event, data: data})
}
}
},
/**
* Stop listening to events
* @param {string|string[]} events - What events to stop listening to
* @param {undefined|handler|handler[]} handlers - What handlers to stop. When undefined, stop all handlers
*/
off(events, handlers) {
for(event of getFlattenedArray(events)) {
arr = map[event] = handlers ? map[event] : []
for(handler of getFlattenedArray(handlers)) {
index = arr.indexOf(handler)
if(index != -1) {
arr.splice(index, 1)
}
}
}
}
}
}
// Terser minified version (325 bytes)
export function eventSystem(){let f,o,e,t,r={},n=f=>[f].flat(1/0);return{on(t,i,p){for(o of n(t))for(e of(f=r[o]??=[],n(i)))-1==f.indexOf(e)&&(p?f.unshift(e):f.push(e))},emit(f,t){for(o of n(f))for(e of r[o]??[])e({type:o,data:t})},off(i,p){for(o of n(i))for(e of(f=r[o]=p?r[o]:[],n(p)))t=f.indexOf(e),-1!=t&&f.splice(t,1)}}}
// test / example code for the eventSystem
{
var test = eventSystem()
function handler1(e) {
console.log('handler1', e)
}
console.log('1. adding handlers for click / whatever')
test.on(
[
'click',
'whatever'
],
[
(e) => {
console.log(e.type, e.data)
},
handler1
]
)
console.log('2. emitting click')
test.emit('click', {t: 200})
console.log('3. emitting whatever')
test.emit('whatever', 'nice')
console.log('4. removing handler1 for click')
test.off('click', handler1)
console.log('5. emitting click')
test.emit('click', {t: 300})
console.log('6. removing all handlers for click')
test.off('click')
console.log('7. emitting click')
test.emit('click', {t: 400})
console.log('8. emitting whatever')
test.emit('whatever', {t: 500})
console.log('9. removing all handlers for whatever')
test.off('whatever')
console.log('10. emitting whatever')
test.emit('whatever', {t: 600})
console.log('11. removing all handlers for bla')
test.off('bla')
console.log('12. emitting bla')
test.emit('bla', {t: 700})
console.log('13. onning single')
test.on('single', handler1)
console.log('14. onning single2')
test.on('single2', handler1)
console.log('15. emitting both')
test.emit(['single', 'single2'], {t: 800})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment