safe-emitter.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. /**
  2. * @fileoverview A variant of EventEmitter which does not give listeners information about each other
  3. * @author Teddy Katz
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Typedefs
  8. //------------------------------------------------------------------------------
  9. /**
  10. * An event emitter
  11. * @typedef {Object} SafeEmitter
  12. * @property {function(eventName: string, listenerFunc: Function): void} on Adds a listener for a given event name
  13. * @property {function(eventName: string, arg1?: any, arg2?: any, arg3?: any)} emit Emits an event with a given name.
  14. * This calls all the listeners that were listening for that name, with `arg1`, `arg2`, and `arg3` as arguments.
  15. * @property {function(): string[]} eventNames Gets the list of event names that have registered listeners.
  16. */
  17. /**
  18. * Creates an object which can listen for and emit events.
  19. * This is similar to the EventEmitter API in Node's standard library, but it has a few differences.
  20. * The goal is to allow multiple modules to attach arbitrary listeners to the same emitter, without
  21. * letting the modules know about each other at all.
  22. * 1. It has no special keys like `error` and `newListener`, which would allow modules to detect when
  23. * another module throws an error or registers a listener.
  24. * 2. It calls listener functions without any `this` value. (`EventEmitter` calls listeners with a
  25. * `this` value of the emitter instance, which would give listeners access to other listeners.)
  26. * @returns {SafeEmitter} An emitter
  27. */
  28. module.exports = () => {
  29. const listeners = Object.create(null);
  30. return Object.freeze({
  31. on(eventName, listener) {
  32. if (eventName in listeners) {
  33. listeners[eventName].push(listener);
  34. } else {
  35. listeners[eventName] = [listener];
  36. }
  37. },
  38. emit(eventName, ...args) {
  39. if (eventName in listeners) {
  40. listeners[eventName].forEach(listener => listener(...args));
  41. }
  42. },
  43. eventNames() {
  44. return Object.keys(listeners);
  45. }
  46. });
  47. };