forEach operator being evaluated without subscription - javascript

I'm trying to teach myself some reactive functional programming. This video from Ben Lesh is showing an example of an observable. My prior reading indicated that an observable is lazy, i.e., it only evaluates after being subscribed to. Strangely enough, this code doesn't require subscription to print to the console.
var Rx = require('rxjs/Rx')
var source = Rx.Observable.from([1,2,3,4,5]);
var newSource = source.filter(x => x % 2 === 1)
.map(x => x + '!')
.forEach(x => console.log(x));
From the RxJS docs:
It seems as though the Observable must be actively resolving the promises emitted by .forEach, I am so confused by this.
Further confusion stems from this code:
var Rx = require('rxjs/Rx')
var source = Rx.Observable.from([1,2,3,4,5]);
var newSource = source.filter(x => x % 2 === 1)
.map(x => x + '!')
.do(x => console.log(x));
Which does not evaluate until running newSource.subscribe();, please help me out to explain the difference behind the two operators here.

Observables are lazy by default. If you perform an operator on an observable, under the hood, rxjs will create a new observable for you that is linked to the previous one. Know that observables are immutable.
However, ForEach is a special kind of operator. It does not return a new Observable but it will subscribe onto the observable under the hood and perform a function on every element emitted by that observable. If you check the source code of the forEach implementation, which is on the Observable class itself you will see the following (just a snippet).
const subscription = this.subscribe((value) => {
if (subscription) {
// if there is a subscription, then we can surmise
// the next handling is asynchronous. Any errors thrown
// need to be rejected explicitly and unsubscribe must be
// called manually
try {
next(value);
} catch (err) {
reject(err);
subscription.unsubscribe();
}
Here we can see the observable is being subscribed to and the value is 'next'-ed. This next function is the function you pass to the forEach call.

Related

.subscribe is not being executed in the correct order

Using Angular and the RxJS library.
I have a simple method:
method(){
const data = this.data;
const moreData = this.moreData;
this.anotherMethodOne(data)
this.anotherMethodTwo(moreData)
}
As you can see I am calling two other methods. anotherMethodOne() should be executed before anotherMethodTwo() - and it is.
Within anotherMethodOne() I have a .subscribe:
anotherMethodOne(data) {
<!-- at this point it jumps out of this method and continues to proceed in the parent method, but returns later -->
this.service.getService(id).subscribe(res => {
res
}
}
As soon as my debugger hits the .subscribe call it jumps back into the parent method() and proceeds to execute this.anotherMethodTwo(moreData). It then jumps back into this.anotherMethodOne(data) to finally complete the .subscribe - however, by this time its too late.
I need to make sure this.anotherMethodOne(data) is completed fully before this.anotherMethodTwo(moreData) runs or ensure that the .subscribe runs before it proceeds any further.
I started looking at switchMap and concat in the RxJS library, but unsure how that would be implemented in my case.
You cannot guarantee an observable would've emitted before proceeding with it's emitted value. So you need to return the observable from the methods and subscribe where it's value is required.
For observable depending on the emissions of other observables, you could use higher order mapping operator like switchMap. More info about them here.
method(){
const data = this.data;
const moreData = this.moreData;
this.anotherMethodOne(data).pipe(
switchMap((someValue) =>
this.anotherMethodTwo(moreData)
)
).subscribe({
// callbacks
});
}
anotherMethodOne(data): Observable<any> {
return this.http.get('url');
}
anotherMethodTwo(moreData): Observable<any> {
return this.http.get('url');
}
When it comes to asynchronous functions, you should stay with the reactive approach and not try to determine when a certain code has finished, but instead just wait for it to finish and then invoke the callback or the responsible handler subsequently. Think about this. What is the subscribe never returns anything - is that okay? What if it takes a really long time to return anything - is that okay too?
But to fix the problem at hand, simply move anotherMethodTwo into the subscription. Then when something is returned, anotherMethodTwo is run.
method(){
const data = this.data;
const moreData = this.moreData;
this.anotherMethodOne(data)
}
anotherMethodOne(data) {
this.service.getService(id).subscribe(res => {
console.log(res)
this.anotherMethodTwo(moreData)
}
}
Going down this path would be similar to async callback hell which nesting style is not recommended but it will do for now.

How can I use Observables instead of Promises?

I have a service with some methods, most of them require a certain callback to be completed before it can do its stuff. With Promises, in pseudo, it is very easy to do this:
ready = http.get(stuff); // Returns a promise, resolves after a while
methodOne() { // methods sometimes called before promise resolves
this.ready.then(_ => {
// doStuff
});
}
methodTwo() {
return this.ready.then(d => {
// doOtherStuff
});
}
Basically I need to do the stuff, only when i'm sure the service is ready.
I actually only need to check if it's ready (what methodOne is doing, just illustrating with methodTwo, that it's easy to more stuff as well).
I want to try and go all in on Observables, but for this specific case, I find it really hard to compete with a similar solution for Observables.
Promises will remember the value and know if it got resolved. An Observable is somewhat more complex and it seems that creating this same flow is troublesome. I need whatever is subscribing to the Observable, to known when it's ready. Some times the method is called early - before the Observable emits and sometimes late, after the Observable already emitted.
I have this right now, but it doesn't seem to work:
this.ready$ = someObservable // Will fire after a litle while but never finish - i only need the first to check though.
.publishReplay(1).refCount(); // Trying to replay if subscription comes after emit.
this.ready$.subscribe(_ => {
// This will be called
});
methodOne() {
this.ready$.subscribe(_ => {
// Not called
});
};
Perhaps i misunderstood the use of publishReplay and refCount?
I think what you're looking for is AsyncSubject. It mimics the promises behavior very well. Here is the description:
The AsyncSubject is a variant where only the last value of the
Observable execution is sent to its observers, and only when the
execution completes.
Here is how it can be used in your case:
subject = new AsyncSubject();
ready = streamOfData(stuff).first().subscribe(subject);
methodOne() {
return this.subject.asObservable();
}
The subject subscribes to the underlying observable returned by the first operator and waits until it's complete. It collects all the subscribers but doesn't send any values to them. As soon as the underlying observable completes it remembers the value and sends it to the collected subscribers. All new future subscribers will be immediately passed this stored resolved value.
Here is the simple example that demonstrates that you can subscribe before or after the observable completes:
const subject = new AsyncSubject();
const o = subject.asObservable();
o.subscribe((v) => {
console.log(v);
});
interval(500).first().subscribe(subject);
setTimeout(() => {
o.subscribe((v) => {
console.log(v);
});
}, 2000);

RXJS chain observables completing at any point

Is there any way to chain several observables but allowing the chain to complete at any time? I have three Observables, they all return booleans. However, I would only want to progress to the next observable in the chain if the current observable is false. The observables must progress upon the completion of the last one and where the completed value is false. Is this possible?
You can setup an observable that control the flow and complete it when you are done. Also use zip operator - it will complete the whole flow if one of the observable(in our case the control one) is completed.
let control$ = new Rx.Subject();
let data$ = Rx.Observable.interval()
.map(x => x<10?true:false)
.do(flag => {
if(flag) control$.next(true);
else control$.complete();
});
Rx.Observable.zip(data$.filter(x=>x), control$.startWith(true), (x,y)=>x)
.subscribe(x=>console.log(x))

How to mimic a "callback with promise" function parameter in rxjs?

I'm an absolute rxjs beginner. For me to start learning to think in observables, I need to translate concepts through code examples. I feel like if I can see the code for this, I can start to do this on my own with other concepts.
I do NOT want to CONVERT a promise to an observable, I want to make a new implementation using Observable that can behave like a promise. How would I re-write the following using Observables?
constructor(){
let makeMessage2 = function(){
return new Promise(resolve, reject){
setTimeout(()=>{
var r = Math.random();
resolve("message two plus random value: " + r );
}, 1000);
}
}
this.logMessageAndResultOfCallback("message one!", makeMessage2);
}
private sideEffect1:string = "";
private sideEffect2:string = "";
logMessageAndResultOfCallback( message1:string, callback:Function ){
console.log(message1);
this.sideEffect1 = message1;
callback().then((message2)=>{
console.log(message2);
this.sideEffect2 = message2;
}
}
I guess the part I don't understand is how to define the "callback" function, how to invoke it. I understand I would wait for the complete or emit handlers, like makeMessage2().subscribe(message2 => console.log(message2)); but I don't have any clue how to define makeMessage2.
This may be totally clueless question, but I've read about 10 different intros to rxjs and this hasn't quite clicked. I just need to map this scenario to observable pattern and I think I can understand it.
Basically, I want to define an observable function myObs() that does not "execute immediately" but "executes" whenever the someMethod(message:string,obs:Observable) is executed. When myObs is executed, it should do something ansynchronously within it (like get the result of a HTTP request) then set the next value, then fire a complete() so my observer defined in someMethod can handle the complete and do something with the result.
Edit: I'm not concerned with the timer or native equivalents in rxjs, this is just to simulate any async action, like getting data from the server.
The code that you wrote and want to 'translate' to observables probably would not work. callback is a promise, not a function, so you can't write callback().
Did you try this introduction too? It worked for many people.
To answer your question, you could write
Rx.Observable.of(""message one!", "message two!")
.map(console.log.bind(console)) // would be better to use `do` operator actually, for semantic reasons, but that works the same here
.subscribe(noop, noop, noop)
or
Rx.Observable.of(""message one!", "message two!")
.subscribe(console.log.bind(console), noop, noop)
where noop is a function that does not do anything, i.e. function noop(){}
In short, your stream emits data, that data flow through a series of operators, and the data flow is started by .subscribe. In your case, you have nothing interesting to do on subscription, because all you do is logging.
Rxjs Streams are in fact callback-based under the hood. You want to check this answer to understand it.
I solved it with help from this guide.
import {Observable} from 'rxjs';
var makeMessage2 = Observable.create(observer => {
// Yield a single value and complete
setTimeout(function(){
let r = Math.random();
observer.next("message two plus random value: " + r );
observer.complete();
}, 1000);
return () => console.log('disposed')
});
logMessageAndResultOfCallback( "some message one", makeMessage2);
logMessageAndResultOfCallback( message1:string, callback:Observeable ){
console.log(message1);
this.sideEffect1 = message1;
var subscription = callback.subscribe(
(value)=>{this.sideEffect2 = value;},
(e) =>{ console.log('onError: %s', e)},
() => {console.log(this.sideEffect2);});
subscription.dispose();
}

Get return value from subcribe on Observable

Using RxJS 5.0.0-rc.1, I'm trying to communicate my Observer and Observable in a way similar to how generators/iterators work by exchanging data using yield and .next(). The intention is to get a hold of what a call to .subscribe returns and modify/update following values in my observable stream depending on that.
I'm not entirely sure if this is, at all, possible. Though, I found out that you can catch exceptions thrown on .subscribe callbacks. The following snippets prints out "Boom!":
var source = Observable.create((observer) => {
try {
observer.next(42);
} catch (e) {
// This will catch the Error
// thrown on the subscriber
console.log(e.message);
}
observer.complete();
});
source.subscribe(() => {
throw new Error('Boom!');
});
So, what if instead of throwing, the subscriber returns a value? Is there a way for the Observable to retrieve it? Perhaps I'm approaching this the wrong way. If so, what's the "reactive" way of doing things in this scenario?
Many thanks.
EDIT
One possible way I came up with is by providing a callback function on every item in the stream. Something like:
var source = Observable.create((observer) => {
// This will print "{ success: true }"
observer.next({ value: 42, reply: console.log });
observer.complete();
});
source.subscribe(({ value, reply }) => {
console.log('Got', value);
return reply({ success: true });
});
Any other thoughts?
EDIT 2
Since my original question brought some confusion on what I was trying to achieve, I'll describe my real world scenario. I'm writing the API of a module for managing messages through queues (much like a simplified, in memory, AMQP-RPC mechanism) and I though RxJS would be a good fit.
It works like you would expect: a Publisher pushes messages to a queue, which get delivered to a Consumer. In term, the Consumer can reply to the Publisher, which can listen to that response if it's interested.
In an ideal scenario, the API would look something like this:
Consumer().consume('some.pattern')
.subscribe(function(msg) {
// Do something with `msg`
console.log(msg.foo);
return { ok: true };
});
Publisher().publish('some.pattern', { foo: 42 })
// (optional) `.subscribe()` to get reply from Consumer
That example would print 42.
The logic for replying to the Publisher lies within the Consumer function. But the actual response comes from the .subscribe() callback. Which leads me to my original question: how should I go about fetching that returned value from the creator of the stream?
Think of Consumer#consume() as:
/**
* Returns an async handler that gets invoked every time
* a new message matching the pattern of this consumer
* arrives.
*/
function waitOnMessage(observer) {
return function(msg) {
observer.next(msg);
// Conceptually, I'd like the returned
// object from `.subscribe()` to be available
// in this scope, somehow.
// That would allow me to go like:
// `sendToQueue(pubQueue, response);`
}
}
return Observable.create((observer) => {
queue.consume(waitOnMessage(observer));
});
Does it make any more sense?
There are indeed similarities between generators and observables. As you can see here, observables (asynchronous sequence of values) are the asynchronous version of iterables (synchronous sequence of values).
Now, a generator is a function which returns an Iterable. However, Rxjs Observable encloses both a generator - a.k.a producer (that you execute/start by calling subscribe) and the produced asynchronous sequence of values (that you observe by passing an Observer object). And the subscribe call returns a Disposable which allows you to stop receiving values (disconnect). So while generators and observables are dual concepts, the APIs to use them differ.
You cannot do two-way communication by default with the rxjs observable API. You probably could manage to do it by constructing yourself the back channel through subjects (note that you MUST have an initial value to kick off the cycle).
var backChannel = Rx.Subject();
backChannel.startWith(initialValue).concatMap(generateValue)
.subscribe(function observer(value){
// Do whatever
// pass a value through the backChannel
backChannel.next(someValue)
})
// generateValue is a function which takes a value from the back channel
// and returns a promise with the next value to be consumed by the observer.
You could consider wrapping that with :
function twoWayObsFactory (yield, initialValue) {
var backChannel = Rx.BehaviorSubject(initialValue);
var next = backChannel.next.bind(backChannel);
return {
subscribe : function (observer) {
var disposable = backChannel.concatMap(yield)
.subscribe(function(x) {
observer(next, x);
});
return {
dispose : function (){disposable.dispose(); backChannel.dispose();}
}
}
}
}
// Note that the observer is now taking an additional parameter in its signature
// for instance
// observer = function (next, yieldedValue) {
// doSomething(yieldedValue);
// next(anotherValue);
// }
// Note also that `next` is synchronous, as such you should avoir sequences
// of back-and-forth communication that is too long. If your `yield` function
// would be synchronous, you might run into stack overflow errors.
// All the same, the `next` function call should be the last line, so order of
// execution in your program is the same independently of the synchronicity of
// the `yield` function
Otherwise, the behaviour you describe seems to be that of an asynchronous generator. I never used such, but as this is a proposal for some future version of javascript, I think you can
already start trying it out with Babel (cf. https://github.com/tc39/proposal-async-iteration).
EDIT :
If you are looking for a loop-back mechanism (less general purpose approach but could very well fits your use case, if what you want to do is simple enough), the expand operator could help. To understand its behaviour, please check the doc, and the following answers on SO for examples of use in concrete contexts:
RxJS: Backpressure with switchMap producing N values
Circular Dependencies with RxJS. Modeling spores
How to build an rx poller that waits some interval AFTER the previous ajax promise resolves?
Basically expand allows you to both emit a value downstream and feed that value back at the same time in your producer.

Categories

Resources