Skip to content

Instantly share code, notes, and snippets.

@jabney
Last active February 15, 2024 17:03
Show Gist options
  • Save jabney/61a56469d1d02f9daa85a93581cd50aa to your computer and use it in GitHub Desktop.
Save jabney/61a56469d1d02f9daa85a93581cd50aa to your computer and use it in GitHub Desktop.
micro-subject: provide basic subscribe/notify/unsubscribe functionality in a dozen or so lines of code
/**
* Provide basic subscribe/notify/unsubscribe functionality in a
* dozen or so lines of code.
*/
/**
* @template T
* @typedef {(value?: T) => void} ObserverFn
*/
/**
* @typedef {() => void} UnsubscribeFn
*/
/**
* @template T
* @typedef {Object} Subject<T>
* @property {(observer: ObserverFn<T>) => UnsubscribeFn} subscribe
* @property {(value?: T) => void} notify
*/
/**
* @template T
*/
const subject = () => {
/**
* Store observers.
*
* @type {Map<number, ObserverFn<T>>}
*/
const map = new Map()
// Track subscription id.
let nextId = 0
/**
* @param {number} id
*
* @returns {void}
*/
const unsubscribe = (id) => void map.delete(id)
/**
* @type {Subject<T>}
*/
const _subject = {
/**
* @param {ObserverFn<T>} observer
*
* @return {UnsubscribeFn}
*/
subscribe(observer) {
if (typeof observer !== 'function') {
throw new Error('<subject.subscribe> observer must be a function')
}
const id = nextId++
map.set(id, observer)
return unsubscribe.bind(null, id)
},
/**
* @param {T} [value]
*
* @returns {void}
*/
notify(value) {
for (const observer of map.values()) {
observer(value)
}
},
}
return _subject
}
export default subject
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment