I am looking at an example of Reason at A First Reason React app for Javascript developers
And I see that he is calling Js.Promise.resolve when using bs-fetch:
RepoData.fetchRepos()
|> Js.Promise.then_(repoData => {
handleReposLoaded(repoData);
Js.Promise.resolve();
})
|> ignore;
I have seen similar code in BuckleScript code as well. For example in Bucklescript Cookbook:
Js.Promise.(
Fetch.fetch "https://api.github.com/users/reasonml-community/repos"
|> then_ Fetch.Response.text
|> then_ (fun text ->
text
|> names
|> Array.iter Js.log
|> resolve)
|> ignore
In JS we usually call resolve when we create a new promise, not when using a function that returns a promise. So why do we need to call resolve in the cases above?
Js.Promise.then_ requires that a new promise is returned.
The reason is that es6 promises aren't soundly typed. The value returned in a then callback is dynamically either wrapped or (infinitely) flattened so that it always returns a promise, and never a nested promise. That means if we allow any value to be returned (let then_: ((_ => 'a), Js.Promise.t(_)) => Js.Promise.t('a)), and if that value is a promise ('a = Js.Promise.t('b)), it would have the return type Js.Promise.t(Js.Promise.t('b)), but the value returned will actually have been flattened to just a Js.Promise.t('b).
Having then_ accept only a promise from the callback alleviates this a bit by making it more obvious that you return a nested promise. It's still possible to resolve a promise however, so the type is still not sound, but it makes it a little bit harder to shoot yourself in the foot.
There will be a sound and elegant promise API in the (probably near) future, but since it's a non-trivial task to design and implement it'll take a bit of time to get it right.
Related
I did this in F# for FRP that works simply as expected:
let print = fun a -> printf "%A\n" a
let event = new Event<_>()
let stream = event.Publish
stream |> Observable.add (fun event -> event |> print)
event.Trigger 5
Although I don't like much about event.publish system, at least, event.Trigger is somewhat straight forward to understand.
Now, I try to get to used to https://reactivex.io/
I have recognized Rx for a long time since its beta release, and I also know this API is very complicated just to do FRP, like with many "rules" like observable / observer and subjectetc., in my view, this is against KISS principle, so haven't touched.
In fact, a weird thing is for an unknown reason, I can't figure out how to do event.Trigger in Rx.
Surely, I googled a lot, and found a little information for this:
RxJS: How would I "manually" update an Observable?
According to this QA, the code for RxJS is
var eventStream = new Rx.Subject();
var subscription = eventStream.subscribe(
function (x) {
console.log('Next: ' + x);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});
var my_function = function() {
eventStream.next('foo');
}
After many trials, I finally discovered that the code below works, with luck
let stream2 = 7 |> Subject.behavior
stream2
|> Observable.map id
|> Observable.subscribe print
|> ignore
stream2.OnNext 99
However, unfortunately, this is only my Guess simply because there's no such a documentation in https://reactivex.io/documentation/subject.html and there is an external documentation http://xgrommx.github.io/rx-book/content/subjects/subject/index.html
The all I know is this code works as intended.
So, my question here is
Is this the only way to "trigger the value" based on the Rx API design?
You seem to undestand Rx basic terms: IObservable and IObserver. These API:s aren't really that complicated. F# makes it even easier since Events implement IObservable out of the box.
It seems that by trigger you mean "make an Observable emit a value" ( OnNext):
If your Observable is created from certain events, triggering such an event will produce a value.
If you want to programatically produce a value using a Subject is fine. As stated in the documentation you pasted, it implements both IObservable and IObserver. E.g. you can call OnNext and Subscribe for the object.
I suggest you consider if and why you really need to programatically produce a value in the Observable. Usually you don't since Observables are created from event sources outside your code. Some cases justify using a Subject such as writing unit tests.
I'm currently using RIBs and ReactorKit to bind networking data.
The problem here is that the network results come out as Observables, which I have a hard time binding to ReactorKit.
Please let me know if there is a way to strip the Observable or turn it into a value.
Just like when BehaviorRelay is .value, the value comes out...
dependency.loadData.getData().flatMap { $0.detailData.flatMap { $0.result }}
====>> Obervable
now what do i do? TT
Please let me know if there is a way to strip the Observable or turn it into a value.
This is called "leaving" or "breaking" the monad and is a code smell.
In production code, it is rarely advised to 'break the monad', especially moving from an observable sequence to blocking methods. Switching between asynchronous and synchronous paradigms should be done with caution, as this is a common root cause for concurrency problems such as deadlock and scalability issues.
-- Intro to Rx
If you absolutely have to do it, then here is a way:
class MyClass {
private (set) var value: Int = 0
private let disposeBag = DisposeBag()
init(observable: Observable<Int>) {
observable
.subscribe(onNext: { [weak self] new in
self?.value = new
}
.disposed(by: disposeBag)
}
}
With the above, when you query value it will have the last value emitted from the observable. You risk race conditions doing this and that's up to you to deal with.
That's the direct answer to your question but it isn't the whole story. In ReactorKit, the API call should be made in your reactor's mutate() function. That function returns an Observable<Mutation> so instead of breaking the monad, you should be just mapping the API response into a Mutation which is likely a specific enum case that is then passed into your reduce() function.
I am trying to download some json, parse it, check some information in the json and depending one the result continue processing or not.
What's the most RxSwift idiomatic way of doing this?
URLSession.shared.rx
.data(request:request)
.observe(on: ConcurrentDispatchQueueScheduler(qos: .background))
.flatMap(parseJson) // into ModelObject
.flatMap(checkModel) // on some condition is there any way to jump into the onCompleted block? if the condition is false then execute processObject
.map(processObject)
.subscribe(
onError: { error in
print("error: \(error)")
}, onCompleted: {
print("Completed with no error")
})
.disposed(by: disposeBag)
where parseJsonis something like:
func parseJson(_ data: Data) -> Single<ModelObject>
checkModel does some checking and if some conditions are fullfilled should complete the sequence without ending in processObject
func checkModel(_ modelObject: ModelObject) -> Single<ModelObject> {
//probably single is not what I want here
}
And finally processObject
func processObject(_ modelObject: ModelObject) -> Completable {
}
This is a bit of a tough question to answer because on the one hand you ask a bog simple question about skipping a map while on the other hand you ask for "most RxSwift idiomatic way of doing this," which would require more changes than simply jumping the map.
If I just answer the basic question. The solution would be to have checkModel return a Maybe rather than a Single.
Looking at this code from a "make it more idiomatic" perspective, a few more changes need to take place. A lot of what I'm about to say comes from assumptions based on the names of the functions and expectations as to what you are trying to accomplish. I will try to call out those assumptions as I go along...
The .observe(on: ConcurrentDispatchQueueScheduler(qos: .background)) is likely not necessary. URLSession already emits on the background.
The parseJson function probably should not return an Observable type at all. It should just return a ModelObject. This assumes that the function is pure; that it doesn't perform any side effect and merely transforms a Data into a ModelObject.
func parseJson(_ data: Data) throws -> ModelObject
The checkModel function should probably not return an Observable type. This really sounds like it should return a Bool and be used to filter the model objects that don't need further processing out. Here I'm assuming again that the function is pure, it doesn't perform any side-effect, it just checks the model.
func checkModel(_ modelObject: ModelObject) -> Bool
Lastly, the processObject function presumably has side effects. It's likely a consumer of data and therefore shouldn't return anything at all (i.e., it should return Void.)
func processObject(_ modelObject: ModelObject)
Udpdate: In your comments you say you want to end with a Completable. Even so, I would not want this function to return a completable because that would make it lazy and thus require you to subscribe even when you just want to call it for its effects.
You can create a generic wrap operator to make any side-effecting function into a Completable:
extension Completable {
static func wrap<T>(_ fn: #escaping (T) -> Void) -> (T) -> Completable {
{ element in
fn(element)
return Completable.empty()
}
}
}
If the above functions are adjusted as discussed above, then the Observable chain becomes:
let getAndProcess = URLSession.shared.rx.data(request:request)
.map(parseJson)
.filter(checkModel)
.flatMap(Completable.wrap(processObject))
.asCompletable()
The above will produce a Completable that will execute the flow every time it's subscribed to.
By setting things up this way, you will find that your base functions are far easier to test. You don't need any special infrastructure, not even RxText to make sure they are correct. Also, it is clear this way that parseJson and checkModel aren't performing any side effects.
The idea is to have a "Functional Core, Imperative Shell". The imperative bits (in this case the data request and the processing) are moved out to the edges while the core of the subscription is kept purely functional and easy to test/understand.
I'm a bit confused by the various definitions of an operator in rxjs.
Below I provide some of the definitions:
1 A Pipeable Operator is a function that takes an Observable as its input and returns another Observable.
Creation Operators are the other kind of operator, which can be called as standalone functions to create a new Observable
2 An operator is a function that takes one observable (the source) as its first argument and returns another observable (the destination, or outer observable)
3 Operators take configuration options, and they return a function that takes a source observable.
4 Operators should always return an Observable [..] If you create a method that returns something other than an Observable, it's not an operator, and that's fine.
Since 1,2,4 seem to be conflicting with 3, which definition is the correct one. Is there a better definition of rxjs operators?
For example: in case of map. Is map() itself the operator? Or the operator is the return value of map()?
Is map() itself the operator? Or the operator is the return value of map()?
Current implementation of the map() looks like this:
export function map<T, R>(project: (value: T, index: number) => R, thisArg?: any): OperatorFunction<T, R> {
return function mapOperation(source: Observable<T>): Observable<R> {
if (typeof project !== 'function') {
throw new TypeError('argument is not a function. Are you looking for `mapTo()`?');
}
return source.lift(new MapOperator(project, thisArg));
};
}
So, map() is a function. It is an operator in RxJS terms, yes, but it's still a regular JavaScript function. That's it.
This operator receives projection callback function which gets called by the map operator. This callback is something you're passing to map(), e.g. value => value.id from this example:
source$.pipe(map(value => value.id))
The return value of the map is also a function (declared as OperatorFunction<T, R>). You can tell that it is a function since map returns function mapOperation().
Now, mapOperation function receives only one parameter: source which is of type Observable<T> and returns another (transformed) Observable<R>.
To summarize, when you say:
A Pipeable Operator is a function that takes an Observable as its input and returns another Observable.
This means that an RxJS operator (which is a function) is pipeable when it takes an Observable as its input and returns another Observable which in our case is true: a map operator indeed returns a function (mapOperation) whose signature ((source: Observable<T>): Observable<R>) indicates exactly that: it takes one Observable and returns another.
An operator is a function that takes one observable (the source) as its first argument and returns another observable (the destination, or outer observable)
I already mentioned couple of times that an operator is a just function.
Operators take configuration options, and they return a function that takes a source observable.
Yes, in this case, a map() could be called operator since it receives configuration option - a projecttion callback function. So, there's really no conflicts here since many operators are configurable.
I'd say that there's conflict in this one:
Operators should always return an Observable [..] If you create a method that returns something other than an Observable, it's not an operator, and that's fine.
I guess that this is an old definition when pipeable operators weren't pipeable. Before pipeable operators were introduced (I think in version 5 of RxJS), operators were returning Observables. An old map() implementation indicates just that.
For more information about why creators of RxJS decided to introduce pipeable operators, please take a look at this document.
Another great article about what are Observables can be found here.
Also:
Creation Operators are the other kind of operator, which can be called as standalone functions to create a new Observable.
of() is an example of creation operator which returns (creates) an Observable. Please take a look at the source code.
TL;DR: A map() is a function that usually has one parameter (a projection callback function) which also returns a function that receives a source Observable and returns a destination Observable.
EDIT: To answer your question from comments, I'd like to do it here.
Yes, in RxJS 6 you can create a function that accepts observable and returns another one and that would be the operator. E.g.
function myOperatorFunction(s: Observable<any>) {
return of(typeof s);
}
and you'd call it like
source$.pipe(myOperatorFunction);
Please notice that I didn't call myOperatorFunction in pipe(), I just passed the reference to it, i.e. I didn't write myOperatorFunction with parenthesis, but without them. That is because pipe receives functions.
In cases where you need to pass some data or callback functions, like in map example, you'd have to have another function that would receive your parameters, just like map receives projection parameter, and use it however you like.
Now, you may wonder why there are operators that don't receive any data, but are still created as functions that return function, like refCount(). That is to coincide with other operators that mostly have some parameters so you don't have to remember which ones don't receive parameters or which ones have default parameters (like min()). In case of refCount, if it was written a bit different than it is now, you could write
source$.pipe(refCountOperatorFunction);
instead of
source$.pipe(refCount());
but you'd have to know that you have to write it this way, so that is the reason why functions are used to return functions (that receives observable and returns another observable).
EDIT 2: Now that you know that built in operators return functions, you could call them by passing in source observable. E.g.
map(value => value.toString())(of())
But this is ugly and not recommended way of piping operators, though it would still work. Let's see it in action:
of(1, 2, true, false, {a: 'b'})
.pipe(
map(value => value.toString()),
filter(value => value.endsWith('e'))
).subscribe(value => console.log(value));
can be also written like this:
filter((value: string) => value.endsWith('e'))(map(value => value.toString())(of(1, 2, true, false, {a: 'b'})))
.subscribe(a => console.log(a));
Although this is a completely valid RxJS code, there's no way you can think of what it does when you read the latter example. What pipe actually does here is that it reduces over all the functions that were passed in and calls them by passing the previous source Observable to the current function.
Yes. map itself is an operator.
Every operator returns an Observable so later on you can subscribe to the Observable you created.
Of course when I say 'you created' I mean that you created via a creation operator or using the Observable class: new Observable
A pipeable operator is just an operator that would be inside the pipe utility function.
Any function that returns a function with a signature of Observable can be piped and that's why you can create your own Observables and pipe operators to it.
I am pretty much sure that you already know all of this and all you want to know is why there is a conflict in what you are reading.
First, you don't have to pipe anything to your Observable.
You can create an Observable and subscribe to it and that's it.
Since you do not have to pipe anything to your Observable, what should we do with the operators?
Are they used only within a pipe?
Answer is NO
As mentioned, an operator takes configuration options, in your example:
const squareValues = map((val: number) => val * val);
and then it returns a new function that takes the source Observable so you can later on subscribe to it:
const squaredNums = squareValues(nums);
As we can see, map took (val: number) => val * val and returned a function that now gets the Observable nums: const nums = of(1, 2, 3);
Behind the scenes map will take the source observable and transform according to the configuration.
Now the important thing:
Instead of doing that in this way (which you can but no need for that), it is better to pipe your operators so you can combine all of the functions (assuming you are using more operators) into one single function.
So again, behind the scenes you can refer to pipe as a cooler way to make operations on your source Observable rather then declaring many variables that uses different operators with some configuration which return a function that takes a source Observable.
I was working on a react project and the following three cases came up. Can someone give me some pointers as to what the differences are when making AJAX request using axios as well as redux-promise?
Case 1 (the payload is undefined - why?):
axios.get(link)
.then(callback)
Case 2 (the payload is also undefined - why?):
axios.get(link)
.then(() => callback())
Case 3 (the payload is the res object):
axios.get(link)
.then((res) => { callback; return res });
Would really appreciate if anyone could please answer this question or give me pointers to materials that could clear my confusion. I did my best researching and have spent couple hours before I posted the question on SO. Thanks!
Your resolved value in the first two promises is undefined because you have a .then() handler that you don't return anything from. The return value of the .then() handler becomes the resolved value of the promise chain.
If you want link to be the resolved value of the promise and you're going to have your own .then() handler, then you have to return it.
Case 1:
axios.get(link).then(callback)
Here you're delegating your .then() handler to the callback function. Unless it returns the value it was passed to it (which apparently it doesn't), then the return value from your .then() handler is undefined and thus that's what the resolved value of the promise chain becomes.
Case 1 is equivalent to this:
axios.get(link).then(function(val) {
return callback(val);
});
So, the promise chain takes on whatever callback(val) returns as the resolved value.
Case 2:
axios.get(link).then(() => callback())
Here, we can clearly see that the return value from the .then() arrow function handler is the result of executing callback() which is apparently undefined so thus the promise chain takes on a resolved value of undefined.
You could fix that by doing this:
axios.get(link).then(() => {
callback()
return link;
});
Case 3:
axios.get(link).then((res) => { callback; return res });
Here's you're explicitly returning res so that becomes the resolved value of the promise chain. You're also not even calling callback(). I presume you meant to have () after it.
Don't mix plain callbacks in with promises
You also probably don't want to mix plain callbacks with promises and they are two different approaches to asynchronous notification and it's much better to use only one technique in a given section of code. Instead, turn the callback operation into one that returns a promise that is resolved when the callback would normally get called. Then, you can just chain promises.
Or, if you're trying to notify some caller about the completion of the operation, then have them just watch the returned promise with their own .then() handler on the returned promise.