Skip to content

Instantly share code, notes, and snippets.

@james4388
Last active November 27, 2019 01:37
Show Gist options
  • Save james4388/26e47ee773bfa1f4050d82b766e261d3 to your computer and use it in GitHub Desktop.
Save james4388/26e47ee773bfa1f4050d82b766e261d3 to your computer and use it in GitHub Desktop.
Implement EventEmitter
class EventEmitter {
constructor (isAsync = false) {
this.events = new Map();
this.isAsync = isAsync; // Allow to notify listener async
}
/*
* Subcribe a callback to an event. Callback will not be duplicate.
* return unsibcribe function
* Usage: const unsub = ee.subcribe(eventName, callback);
* To unsubcribe: unsub()
*/
subcribe (event, callback) {
const listeners = this.events.get(event) || new Set();
listeners.add(callback);
this.events.set(event, listeners);
return this.unsubcribe.bind(this, event, callback);
}
unsubcribe (event, callback) {
const listeners = this.events.get(event);
if (listeners !== undefined) {
listeners.delete(callback);
}
}
emit (event, ...args) {
const listeners = this.events.get(event);
if (listeners !== undefined) {
// if a callback got unsubcribe while iterate it wont' get call
// use [...listeners].forEach to prevent this.
if (this.isAsync) {
// Wrap callback inside promises for async call
Promise.all(
[...listeners].map(
async (callback) => new Promise((approve, reject) => {
approve(callback.apply(null, args));
})
)
);
} else {
listeners.forEach((callback) => {
try {
callback.apply(null, args);
} catch (err) {
// Do something.
}
});
}
}
}
}
/* Async test */
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const ee = new EventEmitter(true);
const unsub1 = ee.subcribe('test', async () => {
await sleep(2000);
console.log('Sub1');
});
const unsub2 = ee.subcribe('test', () => {console.log('Sub2')});
const unsub3 = ee.subcribe('test', () => {console.log('Sub3')});
ee.emit('test')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment