UNPKG

1.65 kBJavaScriptView Raw
1/**
2 * Observable class prototype.
3 *
4 * @module observable
5 */
6
7import * as map from './map.js'
8import * as set from './set.js'
9import * as array from './array.js'
10
11/**
12 * Handles named events.
13 *
14 * @template N
15 */
16export class Observable {
17 constructor () {
18 /**
19 * Some desc.
20 * @type {Map<N, any>}
21 */
22 this._observers = map.create()
23 }
24
25 /**
26 * @param {N} name
27 * @param {function} f
28 */
29 on (name, f) {
30 map.setIfUndefined(this._observers, name, set.create).add(f)
31 }
32
33 /**
34 * @param {N} name
35 * @param {function} f
36 */
37 once (name, f) {
38 /**
39 * @param {...any} args
40 */
41 const _f = (...args) => {
42 this.off(name, _f)
43 f(...args)
44 }
45 this.on(name, _f)
46 }
47
48 /**
49 * @param {N} name
50 * @param {function} f
51 */
52 off (name, f) {
53 const observers = this._observers.get(name)
54 if (observers !== undefined) {
55 observers.delete(f)
56 if (observers.size === 0) {
57 this._observers.delete(name)
58 }
59 }
60 }
61
62 /**
63 * Emit a named event. All registered event listeners that listen to the
64 * specified name will receive the event.
65 *
66 * @todo This should catch exceptions
67 *
68 * @param {N} name The event name.
69 * @param {Array<any>} args The arguments that are applied to the event listener.
70 */
71 emit (name, args) {
72 // copy all listeners to an array first to make sure that no event is emitted to listeners that are subscribed while the event handler is called.
73 return array.from((this._observers.get(name) || map.create()).values()).forEach(f => f(...args))
74 }
75
76 destroy () {
77 this._observers = map.create()
78 }
79}