Closed gitusp closed 5 years ago
Looks pretty reasonable. I think Promise<R, E> → flyd$Stream<Either<R, E>>
is a straightforward conversion and your idea follows it. There was a couple of tickets here in tracker related to your topic. Looks like this is current state of the things to convert.
You've introduced pending state. The minor change is if your widget cannot return to pending state you can just initialize widget in this state and eliminate pending from stream completely. In that case you'll end up with usual Either
.
I've experimented with some dirty approach to this, where I pass raw Error
objects in streams. Anything except Error
is considered to be a data. It's just another way to implement Either
. The main idea is you're not obliged to wrap all your data. You just pass data as usual, but in some cases Error can occur (in that case you still need combinators to extract data or error just like with Either).
@StreetStrider Thank you for your feedback. Now I understand there's cases that the approach cannot apply as you mentioned. I think whether the approach can apply depends on what I focus, the Promise's result or state.
I like the idea to pass raw Error
objects in streams.
There must be varied ways to handle error with stream and each has slightly different meaning.
Although passing raw Error
is almost the same with Either
, it seems that it treats data
and Error
as rather close level things than Either
- Either
explicitly expresses which is "Right" while this approach does not.
I close this issue since my question is resolved. Thank you.
@gitusp I've recalled related discussions #171 #35 #164 you can take a look at them. If any traction someday will occur, I expect it to occur in that tickets.
I'm of the opinion that this is something that should be solved in user land.
The fact is we all have different use cases for converting promises, sometimes we need a loader, sometimes we want to maintain order, sometimes we just want all promises to push to a result stream.
In my codebase I've used:
const promiseToEitherStream = p => {
const s = stream();
p.then(val => s(Right(val))).catch(err => s(Left(err)))
return s
}
const promiseToResultStream = p => {
const s = stream(Left('pending'))
p.then(value => s(Right(value))).catch(error => s(Left(error)))
return s
}
// usage
const result = stream(url)
.map(makeRequest)
.chain(promiseToResultStream)
.map(cata({
Left: R.ifElse(R.equals('pending'), renderLoader, renderError),
Right: renderView
}))
function cata(cata) {
return monad => monad.cata(cata);
}
function renderLoader() {
return <Loader />
}
function renderError(err) {
return <Error error={err} />
}
function renderView(data) {
// ...
}
And in some cases depending on whether ordering must be preserved I use either flyd.fromPromise
or flyd.flattenPromise
.
I don't think flyd should prescribe to it's users how to interact with promises.
I agree with you. promiseToEitherStream
and promiseToResultStream
are both necessary depending on use cases. There should be several ways to convert a promise to a stream.
As you showed, emitting pending
as Left
seems more semantic for me, since pending
is meta information and the domain object is the promise's result.
Hello, thank you for providing this beautiful project. Although I'm not sure whether this question should go here, I'd really like to hear opinions from this community.
As discussed #35, it seems reasonable to convert a Promise into an either-like stream. But I noticed that I usually take another approach to convert Promise. Here I describe my approach:
The concept behind this conversion is that "a Promise must be mapped to one of these state, 'pending' | 'fulfilled' | 'rejected'", as described here.
The first difference between this approach and
flyd.fromPromise
is that the stream created withconvertPromiseIntoStream
emits "pending state" at first. That makes it easy to know in what state a Promise is, and display some loading indicator to user. The second difference is that the stream emits the second state, "fulfilled" | "rejected", after emitting "pending", so it is easy to filter values or reasons into a new stream and handle it.Although I find this approach very efficient, especially building a client application, and think that it should be one of the standard Promise-Stream conversions, I'm wondering if the approach is over simplifying Promise concept, because I know nobody takes the approach and I do not have a deep knowledge in FRP.
I appreciate any feedbacks from you. Thank you.