kefirjs / kefir

A Reactive Programming library for JavaScript
https://kefirjs.github.io/kefir/
MIT License
1.87k stars 97 forks source link

unexpected .scan() behavior #33

Closed RGBboy closed 9 years ago

RGBboy commented 9 years ago

I'm having an issue with the scan method but I am not sure if it just my lack of understanding or if it is a bug.

Here is a stripped down version of what I am trying to achieve:


var Kefir = require('kefir'),
    emitter = Kefir.emitter(),
    scan = emitter.scan(function (acc, value) {
      acc.push(value);
      return acc;
    }, []),
    merged;

emitter.emit(1);
emitter.emit(2);

merged = scan.take(1).concat(emitter);

setTimeout(function () {
  emitter.emit(3);
  emitter.emit(4);
}, 10);

merged.log('merged');

From this I would expect the following log:

// merged <value:current> [ 1, 2 ]
// merged <value> 3
// merged <value> 4

But instead I get:

// merged <value:current> []
// merged <value> [ 3 ]
// merged <value> 4

If I add a subscription to scan with scan.log(); or scan.onValue(function () {}); before emitting anything I get the expected result.

rpominov commented 9 years ago

This isn't a bug. This is happening because until you subscribe to the scan observable it doesn't subscribe to it's parent (emitter observable). So scan doesn't consumes first two values from emitter.

A little more details in the doc http://pozadi.github.io/kefir/#active-state

This idea of lazy subscription is the core of all three libraries (Kefir.js, Bacon.js, and RxJS), although it not ideal it allows to achieve decent performance.

RGBboy commented 9 years ago

What is the recommended way to achieve what I intended?

rpominov commented 9 years ago

Given this code example the only thing that comes to my mind is to add dummy subscriber at the beginning to activate the stream. If you describe bigger problem you trying to solve maybe i'll be able to recommend better solution.

RGBboy commented 9 years ago

Here is what I am trying to achieve. I have server that is accepting connections. On each connection I want to send the client the history of events that has happened so far (ideally as a single object) and also stream new events as they happen.

rpominov commented 9 years ago

Yep, I think adding a dummy subscriber at the beginning is a way to go here.