0

I want to build a custom stream, counting pages recursively:

var pageStream = function(page, limit) {

  return Bacon.fromBinder(function(sink) {p
    if (page >= limit) {
      sink(new Bacon.End());
    } else {
      sink(Bacon.fromArray([page]));
      sink(new Bacon.Next(function() {
        return pageStream(page + 1, limit);
      }));
    }
  }).flatMapConcat(function(v) { return v; });
};


stream = pageStream(1, 5);

// If I use this code nothing is logged, why?
// stream.onEnd(function(v) {
//   console.log('done');
// });

stream.log();

I want pageStream to count up to limit and end the stream. It can count up to the limit, but it doesn't send the final end event.

Also if I listen to stream.onEnd, the stream doesn't work at all.

OlliM
  • 7,023
  • 1
  • 36
  • 47
user3995789
  • 3,452
  • 1
  • 19
  • 35

1 Answers1

2

This task does't require recursion, but if you just want some recursion example, here you go:

var pageStream = function(page, limit) {
  if (page > limit) {
    return Bacon.never();
  } else {
    return Bacon.once(page).concat(pageStream(page + 1, limit));
  }
}

But again I wouldn't recommend this solution as for example for pageStream(1, 5) it generates:

Bacon.once(1).concat(
  Bacon.once(2).concat(
    Bacon.once(3).concat(
      Bacon.once(4).concat(
        Bacon.once(5).concat(
          Bacon.never())))));

Which will perform badly on large numbers.

Instead I would do something like this:

var pageStream = function(page, limit) {
  var arr = [];
  while (page <= limit) {
    arr.push(page);
    page++;
  }
  return Bacon.fromArray(arr);
}

Also if I listen to stream.onEnd, the stream doesn't work at all.

This is classic Bacon pitfall with synchronous streams like .fromArray or .once: https://github.com/baconjs/bacon.js/wiki/FAQ#why-isnt-my-subscriber-called

To avoid this you can use .sequentially() instead of .fromArray(), and .later() instead of .once():

var pageStream = function(page, limit) {
  var arr = [];
  while (page <= limit) {
    arr.push(page);
    page++;
  }
  return Bacon.sequentially(0, arr);
}

var pageStream = function(page, limit) {
  if (page > limit) {
    return Bacon.never();
  } else {
    return Bacon.later(0, page).concat(pageStream(page + 1, limit));
  }
}
Roman Pominov
  • 1,403
  • 1
  • 12
  • 17
  • I don't have a `limit` the recursion is infinite, I want to evaluate lazily, and use it with `take(limit)` eg: `infiniteCountStream().take(10)` – user3995789 Jan 19 '15 at 18:35
  • @user3995789 , take a look at this discussion https://github.com/baconjs/bacon.js/issues/521 maybe you could use the `looper` function from there – Roman Pominov Jan 20 '15 at 19:36