UNPKG

2.18 kBJavaScriptView Raw
1import {extend} from './utils/objects'
2import {VALUE, ERROR, ANY} from './constants'
3import {concat, findByPred, remove, contains} from './utils/collections'
4
5function callSubscriber(type, fn, event) {
6 if (type === ANY) {
7 fn(event)
8 } else if (type === event.type) {
9 if (type === VALUE || type === ERROR) {
10 fn(event.value)
11 } else {
12 fn()
13 }
14 }
15}
16
17function Dispatcher() {
18 this._items = []
19 this._spies = []
20 this._inLoop = 0
21 this._removedItems = null
22}
23
24extend(Dispatcher.prototype, {
25 add(type, fn) {
26 this._items = concat(this._items, [{type, fn}])
27 return this._items.length
28 },
29
30 remove(type, fn) {
31 const index = findByPred(this._items, x => x.type === type && x.fn === fn)
32
33 // if we're currently in a notification loop,
34 // remember this subscriber was removed
35 if (this._inLoop !== 0 && index !== -1) {
36 if (this._removedItems === null) {
37 this._removedItems = []
38 }
39 this._removedItems.push(this._items[index])
40 }
41
42 this._items = remove(this._items, index)
43 return this._items.length
44 },
45
46 addSpy(fn) {
47 this._spies = concat(this._spies, [fn])
48 return this._spies.length
49 },
50
51 // Because spies are only ever a function that perform logging as
52 // their only side effect, we don't need the same complicated
53 // removal logic like in remove()
54 removeSpy(fn) {
55 this._spies = remove(this._spies, this._spies.indexOf(fn))
56 return this._spies.length
57 },
58
59 dispatch(event) {
60 this._inLoop++
61 for (let i = 0, spies = this._spies; this._spies !== null && i < spies.length; i++) {
62 spies[i](event)
63 }
64
65 for (let i = 0, items = this._items; i < items.length; i++) {
66 // cleanup was called
67 if (this._items === null) {
68 break
69 }
70
71 // this subscriber was removed
72 if (this._removedItems !== null && contains(this._removedItems, items[i])) {
73 continue
74 }
75
76 callSubscriber(items[i].type, items[i].fn, event)
77 }
78 this._inLoop--
79 if (this._inLoop === 0) {
80 this._removedItems = null
81 }
82 },
83
84 cleanup() {
85 this._items = null
86 this._spies = null
87 },
88})
89
90export {callSubscriber, Dispatcher}