How does RxJS create or simulate asynchronism? - javascript

I have problems understand the execution model/order of RxJS Observables and Subjects.
I read a lot of literature and blog posts about RxJS observables being the better promise since their subscription can be canceled and they can emit multiple results/values via next().
This question might be answered easily but how does RxJS create or simulate asynchronism?
Does RxJS Observables wrap around promises and create a sequence of promises to make the code execution asynchronous? Or is it because of the implemented observable pattern that change is propagated asynchronous to subscribers but code execution is still synchronous?
In my point of view javascript code is asynchronous when it is handle via callbacks in any of the JavaScript callback queues processed by the event loop.

In RxJS, everything is about producer. The producer can be anything and it can be synchronous or asynchronous, thus Observables can both emit synchronously or asynchronously.
Lets try to understand what is (a)synchronous behavior. I will leave couple of links for deeper understanding of the subject: a talk by Philip Roberts, another talk by Jake Archibald and Jake's blog if you don't like watching long videos.
Tl;dw(atch): all JavaScript code is synchronous and executes within a single thread. On the other hand, WebAPIs, which can be accessed from JS code, may execute some other stuff in other threads and bring back the result to the JavaScript runtime. And the results are passed through to the runtime by Event loop and the callbacks. So, when you say:
In my point of view javascript code is asynchronous when it is handle via callbacks in any of the JavaScript callback queues processed by the event loop.
You're right. A callback handled by the Event loop is the asynchronous callback. Examples of WebAPIs which have asynchronous callbacks are: setTimeout and setInterval, DOM events, XHR events, Fetch events, Web workers, Web sockets, Promises, MutationObserver callbacks and so on. The last two (Promises and MutationObservers) schedule tasks on a different queue (microtask queue), but it's still asynchronous.
Back to RxJS. I already told that in RxJS it's everything about the producer. Observables wrap producers using observers. To quote Ben Lesh from the article:
[A producer] is anything you’re using to get values and pass them to observer.next(value).
This means that the code that is synchronous (and all JS code is) will synchronously emit values when wrapped with an Observable. For example:
import { Observable } from 'rxjs';
const o = new Observable(observer => {
[1, 2, 3].forEach(i => observer.next(i));
observer.complete();
});
o.subscribe(x => console.log(x));
console.log('Anything logged after this?');
Logs:
1
2
3
Anything logged after this?
On the other hand, next example uses setTimeout (which is not part of the ECMAScript specification and uses asynchronous callback):
import { Observable } from 'rxjs';
const o = new Observable(observer => {
setTimeout(() => {
observer.next(1);
observer.complete();
}, 0);
});
o.subscribe(x => console.log(x));
console.log('Anything logged after this?');
Logs this:
Anything logged after this?
1
This means that, even though I subscribed to the source observable before last console.log, we've got the message before observer sent next value. This is because of the asynchronous nature of setTimeout.
In fact, RxJS has many ways of creating Observables so that you don't have to write your own implementations by wrapping all of this.
So, improved first example:
import { from } from 'rxjs';
from([1, 2, 3]).subscribe(i => console.log(i));
console.log('Anything logged after this?');
Or improved second example:
import { of, scheduled, asyncScheduler } from 'rxjs';
scheduled(of(1), asyncScheduler).subscribe(i => console.log(i));
console.log('Anything logged after this?');
scheduled creation operator uses schedulers for dispatching events on different task queues. asyncScheduler internally uses setTimeout to dispatch the event to the macrotask queue, while asapScheduler internally uses Promises as it uses microtask queue.
However, setTimeout is the most obvious and the most repeated example of asynchronous behavior. XHR is the one that is much more interesting to us. Angular's HTTP client does the same wrapping as I did in my first two examples, so that, when response comes, it is transferred to the responseObserver using next.
When the response comes from the server, XMLHttpRequest object puts it to macrotask queue which gets pushed to the call stack by Event loop once call stack is cleared, and the message can be passed to the responseObserver.
This way, the asynchronous event happens, and the subscribers to the Observable that wraps that XMLHttpRequest object get their value asynchronously.
I read a lot of literature and blog posts about RxJS observables being the better promise since their subscription can be canceled and they can emit multiple results/values via next().
The difference between Observables and Promises is indeed in the fact that Observables are cancelable. This is the most important when you're working a lot with WebAPIs as many of them need to have means to be cancelable (so that resources are not lost when we stop using them).
In fact, since RxJS has many creation operators that wrap many of the WebAPIs, they're already dealing with the cancelation stuff for you. All you have to do is to keep track of the subscriptions and to unsubscribe at the right moment. Article that might be helpful for that can be found here.
Does RxJS Observables wrap around promises and create a sequence of promises to make the code execution asynchronous?
No, they wrap a producer. Anything that can call observer.next method. If a producer uses asynchronous callbacks which call observer.next method, then Observables emit asynchronously. Other way around, they emit synchronously.
But, even though original emissions are synchronous, they can be dispatched to be emitted asynchronously by using schedulers.

Good rule of thumb is that in RxJS everything is synchronous unless you work with time. This default behavior has changed between RxJS 4 and RxJS 5+. So for example range(), from() or of() these all are synchronous. All inner subscriptions inside switchMap, mergeMap, forkJoin, etc. are synchronous. This means that you can easily make infinite loops if you emit from subscribe():
const subject$ = new Subject();
const stop$ = new Subject();
subject$.pipe(
tap(() => /* whatever */)
takeUntil(stop),
).subscribe(() => {
subject$.next();
stop$.next();
});
This example will never reach stop$.next().
A common source of confusion is using combineLatest() with synchronous sources. For example both combineLatest() and range() emit synchronously. Try to guess what series of values this chain emits. We want to get all combinations from the two range Observables:
import { combineLatest, range} from 'rxjs';
combineLatest([
range(1, 5),
range(1, 5),
]).subscribe(console.log);
Live demo: https://stackblitz.com/edit/rxjs-p863rv
This emitted only five values where the first number is always 5 which is weird at the first sight. If we want to emit all combinations we would have to chain each range() with delay(0) or use asyncScheduler or use subscribeOn(asyncScheduler) operator to force async behavior.
combineLatest([
range(1, 5, asyncScheduler),
range(1, 5, asyncScheduler),
]).subscribe(console.log);
Live demo: https://stackblitz.com/edit/rxjs-tnxonz

I believe RxJS does not run on Promises internally. It's just how the whole publish-subscribe pattern works. If simplified basically you have Observer, Observable and Subscriber. If you ever created your own observable, you could see that you can wrap it around basically anything: promises, events, http calls even synchronous code like just reading array. The way it's achieved is that Observer has methods next and complete (but not limited to them, e.g. there is also error). Whenever you call .next() on your Observer all subscribers of Observable will have onNext called. That's because through Observable Observer is connected to Subscribers and whenever you call .next() it will call onNext. Where onNext along with onError and onComplete are just callbacks that you're supplying to subscriber when calling .subscribe(). Which means that if you call .next() after a promise resolves it will be asynchronous.
Here is an example:
new Observable<T>((observer: Observer<T>) => {
Promise.resolve(() => {
observer.next()
observer.complete()
})
})
If you subscribe to this observable it will call your onNext asynchronously.
but you can also do something like:
const array = [1,2,3,4,5]
new Observable<T>((observer: Observer<T>) => {
array.forEach((num) => observer.next(num))
observer.complete()
})
Subscribing to this in theory should be synchronous. But you can play around with it. Thing is that rxjs also has such thing as Scheduler which allows you to control the nature of your Observable, but there are also limitations I believe.
There is also a video of simple pattern implementation that helps understanding how it works.

Related

Using delay(0) in combination with refCount()

This article describes the refCount operator and explains that in order to prevent the unsubscription of obervable A we have to add delay(0) to the source observable such that th import { Observable } from "rxjs/Observable";
const source = Observable.defer(() => Observable.of(
Math.floor(Math.random() * 100)
)).delay(0);
Is 0 always enough? In other words does passing zero guarantee that the notification will be delayed until all m.subscribe() statements have run, assuming they are all run immediately following the multicast statement like this:
const m = source.multicast(() => new Subject<number>()).refCount();
m.subscribe(observer("a"));
m.subscribe(observer("b"));
In the above case we are only subscribing observers a and b. If we subscribed a million observers after the multicast statement would running delay(0) still guarantee taht they all will be subscribed before the first source notification happens?
To understand the issue you must know that:
Javascript is single threaded;
Asynchronous events runs in event loop (a.k.a. Micro Task and Macro Task)
When Async event happens, it is added to the Event loop;
After async event added to the Event loop, Javascript continues with synchronous code;
After no synchronous code left, it runs events code from Event loop.
This Observable would be synchronous if you wouldn't add delay(0):
const source = Observable.defer(() => Observable.of(
Math.floor(Math.random() * 100)
)).delay(0);
When first Subscription happens (subscribing is synchronous code), Observable emits immediately, because it is also synchronous. But if you add delay(0) (similar to setTimeout), Javascript will wait until all synchronous code (all source.subscribe() in this case), are executed. After that it will run asynchronous delay(0)).
And here:
const m = source.multicast(() => new Subject<number>()).refCount();
m.subscribe(observer("a"));
m.subscribe(observer("b"));
You have source Observable which becomes asynchronous after its emition is passed to delay(0). At that point, synchronous code will continue (all your other source.subscribe() calls) and after they are done, synchronous delay(0) will emit.
So it is safe even for millions source.subscribe() calls to get executed in this case.
p.s.
multicast(() => new Subject<number>()).refCount() is exactly the same as share() - it takes multicast with Subject factory and counts active subscriptions with refCount.

Promise.all with $q promise and JS event loop

Let's say I have the following code in empty AngularJS controller:
Promise.all([Promise.resolve()]).then(() => console.log('Then'));
setTimeout(() => console.log('setTimeout callback'));
I expect:
Promise.all.then will be put into the event loop.
setTimeout callback will be put into the event loop.
We don't make any long requests and there should be the following output:
Then
setTimeout callback
And it works.
But if we replace Promise.resolve() by $q.resolve():
Promise.all([$q.resolve()]).then(() => console.log('Then'));
setTimeout(() => console.log('setTimeout callback'));
the output will be different:
setTimeout callback
Then
Here is a plunk: https://embed.plnkr.co/0h0i4CzuSgqMbYQtxZtU/
Why is the output different? How does $q.resolve affect the output?
Some reasons:
Promise.all doesn't "detect" already-fulfilled promises, and returns an immediately resolved promise because of that. It always waits for its input promises, using their .then() method (also it needs to assimilate non-native promises through this anyway). Since then callbacks are always asynchronous, the Promise.all(…) result always is resolved asynchronously (unless the iterable is empty), and the Promise.all(…).then(…) callback is scheduled later
There is not a single event queue on the event loop, but multiple ones for different sources. So even if the promise things take more "ticks" of the event loop, their queue is simply served more often than, and before, the timeout queue.
We don't know what mechanism $q is using for making its promise callbacks asynchronous. We only know that it's not the native promise one, and therefore using a different, apparently "slower", queue.
In general, you cannot (should not) rely on asynchronous callbacks to be called in any specific order, except their documentation mentions it. Make the ordering explicit (e.g. using promises) when you need it.

Observable async vs sync

How do I know when an Observable producer is async or sync?
An sync example:
Observable.of([1, 2, 3])
another async example (ngrx Store, see here)
this.store.take(1);
And now an obvious async example:
this.http.get(restUrl)
I fully understand how this works, and that some Observables can be sync and others Async. What I don't understand is how i can tell the difference in advance? Is there for example an obvious interface on the producer that tells me that it will be async?
tl;dr
The main reason this question has come up is because of the answer from the link above (here).
#Sasxa has (correctly) answered that we can use a synchronous call to get the latest value from the ngrx store:
function getState(store: Store<State>): State {
let state: State;
store.take(1).subscribe(s => state = s);
return state;
}
However knowing that observables are usually asynchronous, I saw this and immediately thought RACE CONDITION! the method could return an undefined value before subscribe has called back the function.
I've debugged through the internals of Store and Observable and this example is indeed synchronous, but how should I have known that? For those that know ngrx, the select method of store (used to get the latest values) is asynchronous, without a doubt, as this is what gives us the reactive gui, which is why I came to the assumption I did.
It means that I cannot refactor the code above as follows:
function getLatest(observable: Observable): any {
let obj: any;
observable.take(1).subscribe(latest => obj = latest);
return obj;
}
I could call this with any Observable and it would work for synchronous producers - it may even work SOME OF THE TIME for async producers, but this is without a doubt a race condition if an async observable is passed in.
It is possible to determine if an observable is asynchronous for sure if was directly scheduled with asynchronous scheduler (Scheduler.async or Scheduler.asap), it's exposed as foo$.scheduler:
let schedulers = [null, Scheduler.asap];
let randomScheduler = schedulers[~~(Math.random()*2)]
let foo$ = Observable.of('foo', randomScheduler);
This information becomes even less available when foo$ is processed further, e.g. chained with other operators.
And it's impossible to determine if values will be produced synchronously (on same tick) or asynchronously because this depends on observable internals:
let foo$ = new Observable(observer => {
if (~~(Math.random()*2))
setTimeout(() => observer.next('foo'));
else
observer.next('foo');
});
TL;DR: it's impossible to know this for sure.
It is hard to figure out whether an observable you get is sync or async (imagine you get observables return from a thrid party library). That's why you write it in a fashion that the execution order is controlled and predictable.
That's also why there are operators like concat, combineLatest, forkjoin, switchMap, race, merge to help you get the order and performance right for different scenario

RxJS wait until promise resolved

I'm still figuring out reactive programming so I'm pretty sure this is very basic, but the number of stream transformations is pretty overwhelming to a beginner.
I'm creating an Observable from a DOM event. This event should in turn trigger a REST call and all other DOM events will be ignored until this event has been resolved.
const stream = Observable.fromEvent(document, 'some-event')
stream
.flatMap(() => httpRestService())
.subscribe(() => {
})
How do I ignore the events from the stream until the last HTTP promise has resolved?
DOM event
A - - - - B - - - - C
HTTP event
D ...........done - C
You could try flatMapFirst which seems to do what you want. The following code could work (jsfiddle here - click anywhere) :
const stream = Observable.fromEvent(document, 'some-event')
stream
.flatMapFirst(() => httpRestService())
.subscribe(() => {
})
Quoting the documentation :
The flatMapFirst operator is similar to the flatMap and concatMap methods described above, however, rather than emitting all of the items emitted by all of the Observables that the operator generates by transforming items from the source Observable, flatMapFirst instead propagates the first Observable exclusively until it completes before it begins subscribes to the next Observable. Observables that come before the current Observable completes will be dropped and will not propagate.
UPDATE
Looking at the source code (https://github.com/Reactive-Extensions/RxJS/blob/master/src/core/linq/observable/switchfirst.js) it seems that while the the current observable has not completed, all the incoming observables in the meantime will be discarded, i.e. not subscribed to.
So if subscribing to these observables triggers the http call (would be interesting to see the code for httpRestService), then there is no unnecessary http call. If those calls are triggered immediately by calling the function and the result is passed through an observable, then there is a possibility that those calls are indeed triggered unnecessarily. In which case, that issue is easily solvable with using the defer operator to do the http call only at subscription time. In short, you need lazy execution of the rest request if you don't already have it.

What are the differences between observables and promises in JavaScript?

So i've read that observables are looking to overtake promises in terms of usage in some of upcoming JavaScript MVC's:
Angular 2.0
Falcor used by Netflix
What is the difference between observables and promises?
Updated: Apologies! removed my falsy statement.
What is the difference between observables and promises?
Simply put: A promise resolves to a single value asynchronously, an observable resolves to (or emits) multiple values asynchronously (over time).
Concrete examples:
Promise: Response from an Ajax call
Observable: Click events
More information can be found here: http://reactivex.io/intro.html
i've read that observables are looking to overtake promises
Unlikely. Observables might be the better solution to certain problems, but that doesn't make promises obsolete (if that's what you mean).
Promises are a representation of 1 future value.
Observables are a representation for a possibly infinite amount of values.
Promises will trigger the fetching of that value immediately upon creation.
Observables will only start producing values when you subscribe to them. (Unless it's a hot observable, but that's outside the scope of this question)
Promises are designed to represent AJAX calls.
Observables are designed to represent anything: events, data from databases, data from ajax calls, (possibly infinite) sequences, etc.
Promises offer a very simplistic call back mechanism, where as Rx offers a powerful abstraction over asynchronous programming. An Observable represents a stream of data, which we can then apply operators to in order to define how the incoming data should be treated.
If all you need to do is make an HTTP request and then update a UI component, then using a Promise might suffice.
However, most apps tend to have more complicated needs than that (even if it’s not obvious at the first). Taking our HTTP request for example, let’s see how modelling this as an Observable and using some of the Rx operators can help us:
-If the HTTP request is triggered by a user action, we might want to be wary of firing off multiple HTTP requests (imagine a user typing into a search box). We don’t want to fire a request for every keystroke, so we might want to Throttle our search, so that we only fire a request if the user stops typing for 300ms. Furthermore, if user types a word, waits 300ms, and adds another character, we’ll fire off a subsequent HTTP request. With Promises, we’d probably encounter a race condition as we can’t control the order in which we’ll receive the responses and we can’t cancel old requests. Rx solves this by allowing us to Switch between streams, which calls Dispose on the old request subscriptions we no longer care about. We might also filter out any invalid search inputs, for instance Where the search term is less than 3 characters in length.
-Support for dealing with Timeouts/Error handling. Let’s say our HTTP request fails, Rx allows us to easily Retry making the request.
-Let’s say several parts of our application need to make the same HTTP call, we probably don’t want to actually make the call more than once. We can expose our observable to multiple consumers and use Replay to ensure the call is made once and the result is cached for subsequent subscribers. We can even supply a TimeSpan to Replay, giving us expiring cache behaviour.
-Powerful abstraction over threading through the use of Schedulers, which allows us to control concurrency. Even better, we can use Test Schedulers in our Unit Tests to control time, allowing us to simulate Timeouts, race conditions etc.
These are some quick examples to demonstrate what is possible. There are many more operators within the Rx framework to cater for all types of scenarios and the composability of Rx means you can easily combine operators to define the behaviour you need. It’s also easy to create your own reusable operators (e.g. RetryAfterDelay).
In summary, Rx can do everything than Promises can do, and far far more. I suspect in the next couple of years there'll be a continued shift towards Rx instead of Promises.
For further reading, I'd recommend taking a look at the section on Observables in the Angular 2 guide.
as said in Angular 2 guid
Converting to a Promise is often a good choice when you want to fetch a single chunk of data. so When you receive the data, you're done.
But in some cases requests aren't always done only once. You may start one request, cancel it, and make a different request before the server has
responded to the first request.
for example in a search component As the user types a name into a search box, you'll make repeated HTTP requests by that search query.
A request-cancel-new-request sequence is difficult to implement with
Promises, but easy with Observables.
so if your component gets data with only one request it's a good choice to use Promise but if it has a chain of request-cancel-new request you should use observable
Observables are often compared to promises. Here are some key differences:
Observables are declarative; computation does not start until subscription. Promises execute immediately on creation. This makes observables useful for defining recipes that can be run whenever you need the result.
Observables provide many values. Promises provide one. This makes observables useful for getting multiple values over time.
Observables differentiate between chaining and subscription. Promises only have .then() clauses. This makes observables useful for creating complex transformation recipes to be used by other part of the system, without causing the work to be executed.
Observables subscribe() is responsible for handling errors. Promises push errors to the child promises. This makes observables useful for centralized and predictable error handling.
Best explanation by angular on official website :
https://angular.io/guide/comparing-observables
Observables VS. Promises (by Jeremy Vilken)
In addition to new syntax, observables are a newer pattern for JavaScript applications to
manage asynchronous activities. They’re also a draft for a feature to be natively implemented in the JavaScript language so it has weight behind the pattern. RxJS is the
library we’ll use to help us implement observables in our applications.
Promises are another construct to help deal with asynchronous calls, which are useful
for making API requests, for example. Promises have a major limitation in that they’re
only useful for one call cycle. For example, if you wanted to have a promise return a
value on an event like a user click, that promise would resolve on the first click. But you might be interested in handling every user click action. Normally, you’d use an event
listener for this, and that allows you to handle events over time. This is an important distinction: Observables are like event handlers in that they continue to process data over
time and allow you to continuously handle that stream of data.
When you understand Observables correctly, the differences to Promises are pretty obvious.
The best way to demystify a convoluted concept is to implement it from scratch. Here is an almost purely functional Observable implementation and an example, that wouldn't work with Promises:
/*** Observable type ***/
// type constructor (of a product type)
const proType = name => cons => {
const f = (k, ...args) =>
Object.defineProperties({["run" + name]: k}, {
[Symbol.toStringTag]: {value: name},
[Symbol("args")]: {value: args}
});
return cons(f);
};
// value constructor
const Observable = proType("Observable")
(Observable => k => Observable(k));
/*** Observer factory ***/
const Observer = observer => {
let isUnsubscribed = false;
return {
next: function(x) {
if (isUnsubscribed)
throw new Error("unsubscribed");
else {
try {
return observer.next(x);
}
catch(e) {
isUnsubscribed = true;
this.cancel();
throw e;
}
}
},
error: function(e) {
if (isUnsubscribed)
throw new Error("unsubscribed");
else {
try {
return observer.error(e);
}
catch(e_) {
isUnsubscribed = true;
this.cancel();
throw e_;
}
}
},
complete: function() {
if (isUnsubscribed)
throw new Error("unsubscribed");
else {
try {
const r = observer.complete();
this.cancel();
return r;
}
catch(e) {
isUnsubscribed = true;
cancel();
throw e;
}
}
}
};
};
/*** combinators + auxiliary functions ***/
const subscribe = observable => handlers => {
const observer = Observer(handlers),
cancel = observable.runObservable(observer);
observer.cancel = cancel;
return cancel;
};
const obsMap = f => observable =>
Observable(observer => {
const mapObserver = {
next: x => observer.next(f(x)),
error: e => observer.error(e),
complete: () => observer.complete()
};
return observable.runObservable(mapObserver);
});
/*** main ***/
// create an Observable instance
const numStream = Observable(observer => {
let i = 0;
const timer = setInterval(() => {
observer.next(i++);
}, 1000);
return () => clearTimeout(timer);
});
// map a function over it
const squaredNumStream =
obsMap(x => x * x) (numStream);
// run the observable
const cancel = subscribe(squaredNumStream) ({
next: x => console.log(x),
error: e => console.error(e),
complete: () => console.log("finished")
});
// cancel it
setTimeout(cancel, 11000);
In the example above the Observable squaredNumStream emits a stream of theoretically infinite values asynchronously. You cannot do this with Promises, because they represent a single future value.
I could have easily subscribed to another squaredNumStream without both instances interfering with each other. This is because Observables are unicast, whereas Promises are multicast.
squaredNumStream doesn't run at declaration time, but only after subscription, because Observables are lazily evaluated. Promises on the other hand are eagerly evaluated that is, they start running as soon as you create them.
And finally, Observables are cancelable by design, whereas Promises are hard to cancel due to there unicast semantics.

Categories

Resources