emitter.js 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. 'use strict';
  2. var atoa = require('atoa');
  3. var debounce = require('./debounce');
  4. module.exports = function emitter (thing, options) {
  5. var opts = options || {};
  6. var evt = {};
  7. if (thing === undefined) { thing = {}; }
  8. thing.on = function (type, fn) {
  9. if (!evt[type]) {
  10. evt[type] = [fn];
  11. } else {
  12. evt[type].push(fn);
  13. }
  14. return thing;
  15. };
  16. thing.once = function (type, fn) {
  17. fn._once = true; // thing.off(fn) still works!
  18. thing.on(type, fn);
  19. return thing;
  20. };
  21. thing.off = function (type, fn) {
  22. var c = arguments.length;
  23. if (c === 1) {
  24. delete evt[type];
  25. } else if (c === 0) {
  26. evt = {};
  27. } else {
  28. var et = evt[type];
  29. if (!et) { return thing; }
  30. et.splice(et.indexOf(fn), 1);
  31. }
  32. return thing;
  33. };
  34. thing.emit = function () {
  35. var args = atoa(arguments);
  36. return thing.emitterSnapshot(args.shift()).apply(this, args);
  37. };
  38. thing.emitterSnapshot = function (type) {
  39. var et = (evt[type] || []).slice(0);
  40. return function () {
  41. var args = atoa(arguments);
  42. var ctx = this || thing;
  43. if (type === 'error' && opts.throws !== false && !et.length) { throw args.length === 1 ? args[0] : args; }
  44. et.forEach(function emitter (listen) {
  45. if (opts.async) { debounce(listen, args, ctx); } else { listen.apply(ctx, args); }
  46. if (listen._once) { thing.off(type, listen); }
  47. });
  48. return thing;
  49. };
  50. };
  51. return thing;
  52. };