index.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. const errors = require('./lib/errors')
  2. class EventListener {
  3. constructor () {
  4. this.list = []
  5. }
  6. append (ctx, name, fn, once) {
  7. ctx.emit('newListener', name, fn) // Emit BEFORE adding
  8. this.list.push([fn, once])
  9. }
  10. prepend (ctx, name, fn, once) {
  11. ctx.emit('newListener', name, fn) // Emit BEFORE adding
  12. this.list.unshift([fn, once])
  13. }
  14. remove (ctx, name, fn) {
  15. for (let i = 0, n = this.list.length; i < n; i++) {
  16. const l = this.list[i]
  17. if (l[0] === fn) {
  18. this.list.splice(i, 1)
  19. if (this.list.length === 0) delete ctx._events[name]
  20. ctx.emit('removeListener', name, fn) // Emit AFTER removing
  21. return
  22. }
  23. }
  24. }
  25. removeAll (ctx, name) {
  26. const list = [...this.list]
  27. this.list = []
  28. for (let i = list.length - 1; i >= 0; i--) {
  29. ctx.emit('removeListener', name, list[i][0]) // Emit AFTER removing
  30. }
  31. if (this.list.length === 0) delete ctx._events[name]
  32. }
  33. emit (ctx, name, ...args) {
  34. const list = [...this.list]
  35. for (let i = 0, n = list.length; i < n; i++) {
  36. const l = list[i]
  37. if (l[1] === true) this.remove(ctx, name, l[0])
  38. l[0].call(ctx, ...args)
  39. }
  40. return list.length > 0
  41. }
  42. }
  43. function appendListener (ctx, name, fn, once) {
  44. const e = ctx._events[name] || (ctx._events[name] = new EventListener())
  45. e.append(ctx, name, fn, once)
  46. return ctx
  47. }
  48. function prependListener (ctx, name, fn, once) {
  49. const e = ctx._events[name] || (ctx._events[name] = new EventListener())
  50. e.prepend(ctx, name, fn, once)
  51. return ctx
  52. }
  53. function removeListener (ctx, name, fn) {
  54. const e = ctx._events[name]
  55. if (e !== undefined) e.remove(ctx, name, fn)
  56. return ctx
  57. }
  58. module.exports = exports = class EventEmitter {
  59. constructor () {
  60. this._events = Object.create(null)
  61. }
  62. addListener (name, fn) {
  63. return appendListener(this, name, fn, false)
  64. }
  65. addOnceListener (name, fn) {
  66. return appendListener(this, name, fn, true)
  67. }
  68. prependListener (name, fn) {
  69. return prependListener(this, name, fn, false)
  70. }
  71. prependOnceListener (name, fn) {
  72. return prependListener(this, name, fn, true)
  73. }
  74. removeListener (name, fn) {
  75. return removeListener(this, name, fn)
  76. }
  77. on (name, fn) {
  78. return appendListener(this, name, fn, false)
  79. }
  80. once (name, fn) {
  81. return appendListener(this, name, fn, true)
  82. }
  83. off (name, fn) {
  84. return removeListener(this, name, fn)
  85. }
  86. emit (name, ...args) {
  87. const e = this._events[name]
  88. return e === undefined ? false : e.emit(this, name, ...args)
  89. }
  90. listeners (name) {
  91. const e = this._events[name]
  92. return e === undefined ? [] : [...e.list]
  93. }
  94. listenerCount (name) {
  95. const e = this._events[name]
  96. return e === undefined ? 0 : e.list.length
  97. }
  98. getMaxListeners () {
  99. return EventEmitter.defaultMaxListeners
  100. }
  101. setMaxListeners (n) {}
  102. removeAllListeners (name) {
  103. if (arguments.length === 0) {
  104. for (const key of Reflect.ownKeys(this._events)) {
  105. if (key === 'removeListener') continue
  106. this.removeAllListeners(key)
  107. }
  108. this.removeAllListeners('removeListener')
  109. } else {
  110. const e = this._events[name]
  111. if (e !== undefined) e.removeAll(this, name)
  112. }
  113. return this
  114. }
  115. }
  116. exports.EventEmitter = exports
  117. exports.defaultMaxListeners = 10
  118. exports.on = function on (emitter, name, opts = {}) {
  119. const {
  120. signal
  121. } = opts
  122. if (signal && signal.aborted) {
  123. throw errors.OPERATION_ABORTED(signal.reason)
  124. }
  125. let error = null
  126. let done = false
  127. const events = []
  128. const promises = []
  129. emitter.on(name, onevent)
  130. if (name !== 'error') emitter.on('error', onerror)
  131. if (signal) signal.addEventListener('abort', onabort)
  132. return {
  133. next () {
  134. if (events.length) {
  135. return Promise.resolve({ value: events.shift(), done: false })
  136. }
  137. if (error) {
  138. const err = error
  139. error = null
  140. return Promise.reject(err)
  141. }
  142. if (done) return onclose()
  143. return new Promise((resolve, reject) =>
  144. promises.push({ resolve, reject })
  145. )
  146. },
  147. return () {
  148. return onclose()
  149. },
  150. throw (err) {
  151. return onerror(err)
  152. },
  153. [Symbol.asyncIterator] () {
  154. return this
  155. }
  156. }
  157. function onevent (...args) {
  158. if (promises.length) {
  159. promises.shift().resolve({ value: args, done: false })
  160. } else {
  161. events.push(args)
  162. }
  163. }
  164. function onerror (err) {
  165. if (promises.length) {
  166. promises.shift().reject(err)
  167. } else {
  168. error = err
  169. }
  170. return Promise.resolve({ done: true })
  171. }
  172. function onabort () {
  173. onerror(errors.OPERATION_ABORTED(signal.reason))
  174. }
  175. function onclose () {
  176. emitter.off(name, onevent)
  177. if (name !== 'error') emitter.off('error', onerror)
  178. if (signal) signal.removeEventListener('abort', onabort)
  179. done = true
  180. if (promises.length) promises.shift().resolve({ done: true })
  181. return Promise.resolve({ done: true })
  182. }
  183. }
  184. exports.once = function once (emitter, name, opts = {}) {
  185. const {
  186. signal
  187. } = opts
  188. if (signal && signal.aborted) {
  189. throw errors.OPERATION_ABORTED(signal.reason)
  190. }
  191. return new Promise((resolve, reject) => {
  192. if (signal) signal.addEventListener('abort', onabort)
  193. emitter.once(name, (...args) => {
  194. if (signal) signal.removeEventListener('abort', onabort)
  195. resolve(args)
  196. })
  197. function onabort () {
  198. reject(errors.OPERATION_ABORTED(signal.reason))
  199. }
  200. })
  201. }