Closed beckyconning closed 10 years ago
It seems to work if it the EventStream isn't started with fromPromise http://nullzzz.blogspot.co.uk/2012/12/baconjs-tutorial-part-iii-ajax-and-stuff.html
Shouldn't this log 0 and 1 rather than just 1?
Bacon.fromPromise(Promise.fulfilled(0))
.flatMap(function (n) { return Bacon.fromPromise(Promise.fulfilled(n+1)); })
.log();
Your example is essentially the same as
Promise.fulfilled(0)
.then(function (n) { return Promise.fulfilled(n + 1); })
.done(console.log)
I guess it should log only single 1
.
Bacon.fromPromise
is based on the assumption that a promise yields at most 1 value. "A promise represents the eventual value returned from the single completion of an operation" http://wiki.commonjs.org/wiki/Promises/A
Not sure what you're trying to accomplish in your example, but it seems you're creating a non-terminating recursively constructing stream where you always poll for more stuff from the server and never output anything.
Ah ok. I can see now that this is the defined behaviour of the methods I was using. Is it possible achieve the effect of:
Changes feed example:
Bacon.fromPromise(getChangesSince(0))
.mergeFlatMapLatest(function getSubsequentChanges(changes) {
return Bacon.fromPromise(getChangesSince(changes[“last_seq”])
.mergeFlatMapLatest(getSubsequentChanges);
});
})
.map(function (changes) { return changes[“results”]; )
.flatMap(Bacon.fromArray)
.log();
The equivalent with Javascript Arrays would be:
var g = function (xs, f) {
return xs.map(function (x) { return [x, f(x)]; })
.reduce(function (x, y) { return x.concat(y); });
};
and with Haskell Lists would be:
g :: [a] -> (a -> a) -> [a]
g xs f = concat $ map (\x -> [x, f x]) xs
For active streams like those originating from Bacon.interval this can be done by adding this method to EventStream:
mergeFlatMapLatest: (right) ->
left = this
rightStream = left.flatMapLatest(right)
withDescription(left, "mergeFlatMapLatest", right, left.merge(rightStream))
This won't work if the steam that this method is called on originates from Bacon.once. It does seem to work on streams originating form Bacon.fromPromise though:
Bacon.fromPromise(P.fulfilled(1))
.mergeFlatMapLatest(function (x) { return B.fromPromise(P.fulfilled(x + 1)); })
.log();
The above gives:
1
2
<end>
Which also lets you do:
var forever = function (x) {
return Bacon.fromPromise(Promise.fulfilled(x + 1).delay(1000)).mergeFlatMapLatest(forever);
};
Bacon.fromPromise(P.fulfilled(0)).mergeFlatMapLatest(forever).log();
Which is a polling pattern that can be applied to all sorts of asynchronous actions.
A longer term goal might be making merge more composable?
Also I normally use spies to unit-test functions in terms of other functions but there doesn't seem to be any spy testing stuff in BaconSpec.coffee. What would the best way of writing a test for a method like this?
Actually let me open a new issue for this.
A promise can be a great starting point for an EventStream. However limiting an EventStream's lifespan to the fulfilment or rejection of that promise is really restricting.
In this example we repeatedly long-poll for changes.
This seems so useful to me but its impossible with the current restriction on fromPromise. I am quite new to Bacon.js though, so I might have made a mistake that I can't see.
Maybe this restriction could be default but turn-off-able.