3

I have a I have a stream of numbers, I have to turn them into a stream of posts using a promise. And I want to do this lazily. So if I do .take(1) from the post stream, it will turn only one number to a post.

This is the promise that gets a post from a number:

var getPost = function(author) {
  console.log('get post' + author);
  return new RSVP.Promise(function(resolve, reject) {
    setTimeout(function() {
      var result = "Post by " + author;
      resolve(result);
    }, 1000);
  });
};

I am only interested in first post, thus take(1), and It should call getPost once.

If I use map, the stream works lazy, calls getPost once. If I use flatmap, it calls getPost for all the numbers.

var lazyStream = Bacon.fromArray([1, 2, 3, 4]).map(function(value) {
  return Bacon.fromPromise(getPost(value));
});

var nonLazyStream = Bacon.fromArray([1, 2, 3, 4]).flatMap(function(value) {
  return Bacon.fromPromise(getPost(value));
});

lazyStream.take(2).log();
//nonLazyStream.take(2).log();

However map returns a promise, while flatMap returns the post itself. How do I have a lazy stream that returns the value of promise?

Roman Kiselenko
  • 43,210
  • 9
  • 91
  • 103
user3995789
  • 3,452
  • 1
  • 19
  • 35
  • @BenjaminGruenbaum, thanks so much, that works, I am confused how/why this works, an explanation and/or an alternative better solution will be accepted. Because it looks to me like `flatMapWithConcurrencyLimit` is a side effect that solves this problem. – user3995789 Dec 26 '14 at 13:38
  • I've added more details, let me know if it is clearer now. – Benjamin Gruenbaum Dec 26 '14 at 13:40

1 Answers1

2

flatMap takes all the streams created by the promises at once and spawns a new stream using all of the streams at once. Live you have observed this is not lazy and will call all the promise returning functions at once.

You want that to happen one at a time so you should use flatMapConcat. Instead of taking all the streams at once it will call them one at a time invoking the promises one by one - this is what you'd normally expect .flatMap to do in some other FRP libraries. Note that this generalizes using flatMapWithConcurrencyLimit if you ever need it to do n at a time.

Here is an example using flatMapConcat for a similar case:

function delayPromise(val){ // delayed promise simulating an async request
    return new Promise(function(resolve){
      setTimeout(function(){ console.log("Resolve timeout"); resolve(val); }, 500);  
    });
}

var stream = Bacon.fromArray([1, 2, 3, 4]).flatMapConcat(function(value) {
  return Bacon.fromPromise(delayPromise(value));
});

stream.take(1).log();

Fiddle link

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504