baconjs/bacon.js — pull request #450 by lautis (2014-11-01 22:30:18+00:00)
Title: Implement dispatchers with prototypes

Implement dispatchers and Bus using prototypes. Some other minor optimisations to reduce number of closures and make code better optimisable. Empty EventStream memory footprint is reduced form 1.11KiB to 0.23KiB.

Breaking(?) changes:

* Dispatcher::push is not bound to the dispatcher instance
* Bus::push is not bound to the dispatcher instance

Below are results from memory tests and performance tests in Chrome. Running performance tests in Node seems to result in worse results, especially for `flatMap`. However, in Chrome, flatMap is faster than in master.

## Memory

Before:

```
new EventStream
w/o subscription 1.11 KiB ± 3.22 KiB
with subscription 0.66 KiB ± 1.16 KiB
unsubscribe -0.71 KiB ± 0.04 KiB
subscribe again 0.88 KiB ± 0.03 KiB
unsubscribe again -0.85 KiB ± 0.01 KiB

new Bus()
w/o subscription 3.10 KiB ± 0.01 KiB
with subscription 0.84 KiB ± 0.18 KiB
unsubscribe -0.59 KiB ± 0.01 KiB
subscribe again 0.73 KiB ± 0.01 KiB
unsubscribe again -0.72 KiB ± 0.00 KiB

Bacon.once(1)
w/o subscription 2.36 KiB ± 0.05 KiB
with subscription 1.39 KiB ± 0.15 KiB
unsubscribe -0.56 KiB ± 0.01 KiB
subscribe again 0.28 KiB ± 0.01 KiB
unsubscribe again -0.27 KiB ± 0.00 KiB

Bacon.never()
w/o subscription 2.29 KiB ± 0.01 KiB
with subscription 1.16 KiB ± 0.20 KiB
unsubscribe -0.54 KiB ± 0.00 KiB
subscribe again 0.28 KiB ± 0.01 KiB
unsubscribe again -0.28 KiB ± 0.01 KiB

EventStream::toProperty(1)
w/o subscription 5.05 KiB ± 0.03 KiB
with subscription 2.28 KiB ± 0.16 KiB
unsubscribe -1.15 KiB ± 0.01 KiB
subscribe again 1.75 KiB ± 0.05 KiB
unsubscribe again -1.46 KiB ± 0.00 KiB

EventStream::toProperty(1).changes()
w/o subscription 6.90 KiB ± 0.05 KiB
with subscription 2.78 KiB ± 0.18 KiB
unsubscribe -1.43 KiB ± 0.01 KiB
subscribe again 2.25 KiB ± 0.01 KiB
unsubscribe again -1.96 KiB ± 0.00 KiB

EventStream::map(noop)
w/o subscription 5.24 KiB ± 0.01 KiB
with subscription 1.76 KiB ± 0.18 KiB
unsubscribe -0.94 KiB ± 0.01 KiB
subscribe again 1.71 KiB ± 0.01 KiB
unsubscribe again -1.60 KiB ± 0.00 KiB

EventStream::filter(noop)
w/o subscription 5.24 KiB ± 0.01 KiB
with subscription 1.76 KiB ± 0.19 KiB
unsubscribe -0.94 KiB ± 0.01 KiB
subscribe again 1.70 KiB ± 0.00 KiB
unsubscribe again -1.60 KiB ± 0.00 KiB

EventStream::scan(0, noop)
w/o subscription 4.94 KiB ± 0.01 KiB
with subscription 2.26 KiB ± 0.20 KiB
unsubscribe -1.14 KiB ± 0.01 KiB
subscribe again 1.72 KiB ± 0.00 KiB
unsubscribe again -1.46 KiB ± 0.01 KiB

Bacon.sequentially(0, [1, 2])
w/o subscription 2.52 KiB ± 0.01 KiB
with subscription 1.57 KiB ± 0.12 KiB
unsubscribe -1.20 KiB ± 0.09 KiB
subscribe again 1.48 KiB ± 0.16 KiB
unsubscribe again -1.34 KiB ± 0.08 KiB

EventStream::take(5)
w/o subscription 5.08 KiB ± 0.01 KiB
with subscription 1.77 KiB ± 0.18 KiB
unsubscribe -0.94 KiB ± 0.00 KiB
subscribe again 1.68 KiB ± 0.01 KiB
unsubscribe again -1.60 KiB ± 0.00 KiB

EventStream::flatMap(noop)
w/o subscription 4.12 KiB ± 0.01 KiB
with subscription 2.82 KiB ± 0.16 KiB
unsubscribe -2.39 KiB ± 0.01 KiB
subscribe again 2.68 KiB ± 0.03 KiB
unsubscribe again -2.57 KiB ± 0.01 KiB

EventStream::combine(stream, noop)
w/o subscription 12.72 KiB ± 0.23 KiB
with subscription 5.31 KiB ± 0.17 KiB
unsubscribe -3.99 KiB ± 0.01 KiB
subscribe again 4.93 KiB ± 0.01 KiB
unsubscribe again -4.84 KiB ± 0.01 KiB

EventStream::combineAsArray(stream1, stream2, stream3, stream4)
w/o subscription 14.08 KiB ± 0.02 KiB
with subscription 7.14 KiB ± 0.24 KiB
unsubscribe -5.86 KiB ± 0.06 KiB
subscribe again 6.60 KiB ± 0.01 KiB
unsubscribe again -6.54 KiB ± 0.01 KiB

EventStream::mergeAll(stream1, stream2, stream3, stream4)
w/o subscription 9.29 KiB ± 0.01 KiB
with subscription 4.86 KiB ± 0.24 KiB
unsubscribe -4.13 KiB ± 0.01 KiB
subscribe again 4.56 KiB ± 0.01 KiB
unsubscribe again -4.48 KiB ± 0.01 KiB

Diamond-shaped Property graph
w/o subscription 1.89 MiB ± 0.00 MiB
with subscription 0.77 MiB ± 0.00 MiB
unsubscribe -0.56 MiB ± 0.00 MiB
subscribe again 0.73 MiB ± 0.01 MiB
unsubscribe again -0.73 MiB ± 0.01 MiB

Bacon.combineTemplate
w/o subscription 1.32 MiB ± 0.00 MiB
with subscription 0.52 MiB ± 0.00 MiB
unsubscribe -411.78 KiB ± 0.37 KiB
subscribe again 0.50 MiB ± 0.00 MiB
unsubscribe again -0.50 MiB ± 0.00 MiB
```

After:

```
new EventStream
w/o subscription 0.23 KiB ± 3.22 KiB
with subscription 1.07 KiB ± 1.16 KiB
unsubscribe -0.87 KiB ± 0.03 KiB
subscribe again 1.04 KiB ± 0.07 KiB
unsubscribe again -1.00 KiB ± 0.02 KiB

new Bus()
w/o subscription 1.77 KiB ± 0.03 KiB
with subscription 1.27 KiB ± 0.19 KiB
unsubscribe -0.75 KiB ± 0.00 KiB
subscribe again 0.89 KiB ± 0.02 KiB
unsubscribe again -0.88 KiB ± 0.01 KiB

Bacon.once(1)
w/o subscription 1.30 KiB ± 0.02 KiB
with subscription 1.47 KiB ± 0.17 KiB
unsubscribe -0.69 KiB ± 0.01 KiB
subscribe again 0.27 KiB ± 0.02 KiB
unsubscribe again -0.27 KiB ± 0.00 KiB

Bacon.never()
w/o subscription 1.22 KiB ± 0.01 KiB
with subscription 1.34 KiB ± 0.19 KiB
unsubscribe -0.67 KiB ± 0.01 KiB
subscribe again 0.27 KiB ± 0.00 KiB
unsubscribe again -0.29 KiB ± 0.00 KiB

EventStream::toProperty(1)
w/o subscription 2.97 KiB ± 0.16 KiB
with subscription 3.13 KiB ± 0.21 KiB
unsubscribe -1.42 KiB ± 0.01 KiB
subscribe again 1.95 KiB ± 0.11 KiB
unsubscribe again -1.79 KiB ± 0.00 KiB

EventStream::toProperty(1).changes()
w/o subscription 3.97 KiB ± 0.03 KiB
with subscription 4.16 KiB ± 0.18 KiB
unsubscribe -1.84 KiB ± 0.01 KiB
subscribe again 2.57 KiB ± 0.02 KiB
unsubscribe again -2.45 KiB ± 0.01 KiB

EventStream::map(noop)
w/o subscription 2.88 KiB ± 0.01 KiB
with subscription 3.27 KiB ± 0.19 KiB
unsubscribe -1.48 KiB ± 0.00 KiB
subscribe again 2.09 KiB ± 0.00 KiB
unsubscribe again -2.07 KiB ± 0.01 KiB

EventStream::filter(noop)
w/o subscription 2.88 KiB ± 0.01 KiB
with subscription 3.27 KiB ± 0.18 KiB
unsubscribe -1.48 KiB ± 0.01 KiB
subscribe again 2.10 KiB ± 0.01 KiB
unsubscribe again -2.08 KiB ± 0.00 KiB

EventStream::scan(0, noop)
w/o subscription 2.83 KiB ± 0.01 KiB
with subscription 3.14 KiB ± 0.19 KiB
unsubscribe -1.41 KiB ± 0.00 KiB
subscribe again 1.91 KiB ± 0.02 KiB
unsubscribe again -1.80 KiB ± 0.01 KiB

Bacon.sequentially(0, [1, 2])
w/o subscription 1.60 KiB ± 0.01 KiB
with subscription 2.08 KiB ± 0.12 KiB
unsubscribe -1.37 KiB ± 0.09 KiB
subscribe again 1.61 KiB ± 0.16 KiB
unsubscribe again -1.50 KiB ± 0.08 KiB

EventStream::take(5)
w/o subscription 2.75 KiB ± 0.01 KiB
with subscription 3.30 KiB ± 0.17 KiB
unsubscribe -1.49 KiB ± 0.00 KiB
subscribe again 2.06 KiB ± 0.01 KiB
unsubscribe again -2.08 KiB ± 0.01 KiB

EventStream::flatMap(noop)
w/o subscription 2.39 KiB ± 0.01 KiB
with subscription 3.84 KiB ± 0.16 KiB
unsubscribe -2.50 KiB ± 0.05 KiB
subscribe again 2.91 KiB ± 0.03 KiB
unsubscribe again -2.90 KiB ± 0.01 KiB

EventStream::combine(stream, noop)
w/o subscription 7.92 KiB ± 0.20 KiB
with subscription 7.97 KiB ± 0.16 KiB
unsubscribe -4.69 KiB ± 0.01 KiB
subscribe again 5.61 KiB ± 0.00 KiB
unsubscribe again -5.62 KiB ± 0.01 KiB

EventStream::combineAsArray(stream1, stream2, stream3, stream4)
w/o subscription 8.71 KiB ± 0.01 KiB
with subscription 10.28 KiB ± 0.25 KiB
unsubscribe -6.64 KiB ± 0.01 KiB
subscribe again 7.40 KiB ± 0.01 KiB
unsubscribe again -7.52 KiB ± 0.01 KiB

EventStream::mergeAll(stream1, stream2, stream3, stream4)
w/o subscription 5.07 KiB ± 0.01 KiB
with subscription 7.41 KiB ± 0.26 KiB
unsubscribe -4.69 KiB ± 0.01 KiB
subscribe again 5.20 KiB ± 0.01 KiB
unsubscribe again -5.29 KiB ± 0.01 KiB

Diamond-shaped Property graph
w/o subscription 1.15 MiB ± 0.00 MiB
with subscription 1.31 MiB ± 0.01 MiB
unsubscribe -0.76 MiB ± 0.01 MiB
subscribe again 0.92 MiB ± 0.02 MiB
unsubscribe again -0.97 MiB ± 0.06 MiB

Bacon.combineTemplate
w/o subscription 0.86 MiB ± 0.00 MiB
with subscription 0.80 MiB ± 0.00 MiB
unsubscribe -462.64 KiB ± 0.78 KiB
subscribe again 0.63 MiB ± 0.00 MiB
unsubscribe again -0.60 MiB ± 0.00 MiB
```

## Browser performance

Before:

```
diamond x 31.96 ops/sec ±5.73% (37 runs sampled)
combo x 47.26 ops/sec ±8.64% (39 runs sampled)
zip x 968 ops/sec ±3.50% (54 runs sampled)
flatMap x 95.35 ops/sec ±4.21% (48 runs sampled)
Bacon.combineTemplate.sample x 157 ops/sec ±3.60% (49 runs sampled)
Bacon.combineTemplate (deep) x 8.63 ops/sec ±7.73% (26 runs sampled)
Bacon.combineTemplate x 128 ops/sec ±2.72% (50 runs sampled)
EventStream.map x 3,087 ops/sec ±3.69% (56 runs sampled)
EventStream.scan x 2,900 ops/sec ±5.72% (19 runs sampled)
EventStream.toProperty x 3,320 ops/sec ±5.04% (22 runs sampled)
```

After:

```
diamond x 43.95 ops/sec ±6.18% (42 runs sampled)
combo x 69.15 ops/sec ±4.01% (42 runs sampled)
zip x 982 ops/sec ±2.72% (56 runs sampled)
flatMap x 144 ops/sec ±5.44% (54 runs sampled)
Bacon.combineTemplate.sample x 241 ops/sec ±2.59% (56 runs sampled)
Bacon.combineTemplate (deep) x 9.92 ops/sec ±4.34% (29 runs sampled)
Bacon.combineTemplate x 124 ops/sec ±2.44% (49 runs sampled)
EventStream.map x 2,913 ops/sec ±4.67% (20 runs sampled)
EventStream.scan x 2,769 ops/sec ±2.43% (57 runs sampled)
EventStream.toProperty x 3,864 ops/sec ±10.59% (25 runs sampled)
```