Promise.all with $q promise and JS event loop - javascript

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.

Related

How does this promise without an argument work in this mutation observer?

I was looking at this mutation obersver in some typescript code and I can’t figure how the promise works in it, I’ve not see a promise without an argument in this style before:
const observer = new MutationObserver((mutations: MutationRecord[]) => {
Promise.resolve().then(someNextMethod)
this.somethingThatTakesAWhile()
})
observer.observe(HTMLtarget)
When the observation is triggered the someNextMethod runs after this.somethingThatTakesAWhile() has ran. How is this possible in this instance? I don't understand how the Promise get passed any arguments and knows how to resolve in this case. Could someone explain the internal mechanics of this code please? I'm at a bit of a loss as to how it runs in that order. Thanks!
The main point of something like this:
Promise.resolve().then(someNextMethod)
is just to call someNextMethod() after the current chain of execution finishes. In a browser, it is similar to this:
setTimeout(someNextMethod, 0);
though the Promise.resolve() method will prioritize it sooner than setTimeout() if other things are waiting in the event queue.
So, in your particular example, the point of these two statements:
Promise.resolve().then(someNextMethod)
this.somethingThatTakesAWhile()
is to call someNextMethod() after this.somethingThatTakesAWhile() returns and after the MutationObserver callback has returned, allowing any other observers to also be notified before someNextMethod() is called.
As to why this calls someNextMethod() later, that's because all .then() handlers run no sooner than when the current thread of execution completes (and returns control back to the event loop), even if the promise they are attached to is already resolved. That's how .then() works, per the Promise specification.
Why exactly someone would do that is context dependent and since this is all just pseudo-code, you don't offer any clues as to the real motivation here.
This:
Promise.resolve().then(someNextMethod)
Is equivalent to this:
Promise.resolve().then(() => someNextMethod())
Working backward is equivalent to:
const myNewMethod = () => someNextMethod()
Promise.resolve().then(myNewMethod)
Defining a function inline or pointing to a function is just a syntactical difference. All of the arguments passed through then will be passed to the referenced function. But in this case, there isn't any as it's a promise with an empty return value.
In other words, the method doesn't need any parameters. In this instance it's actually just an old JS hack/trick to get the code to run at the end of the call stack.

Can JavaScript execute two asynchronous functions or callbacks at the same time? [duplicate]

I am new to Javascript and Ascynchronous programming, and a few things confuse me, please point out the misfacts in my learning.
Callbacks of an Asynchronous function are put in a message queue and
executed via event loop.
Asynchronous execution is non-blocking, done
via event loop.
Functions like setTimeout are asynchronous.
Asynchronous functions are blocking, only their callbacks are
non-blocking.
If any of the above are wrong, please elaborate it.
Callbacks of an Asynchronous function are put in a message queue and executed via event loop.
No.
There are generally two kinds of asynchronous functions - ones that take some sort of callback to run when they are done and ones that produce a Promise as a result.
Callback-based functions
This is an example of a callback-based function:
setTimeout(() => console.log("foo"), 0);
console.log("bar");
/* output:
bar
foo
*/
setTimeout will delay a callback to be executed later. Even with a timeout of zero milliseconds, it still schedules the callback until after the current execution is complete, so the order is:
setTimeout schedules the callback.
console.log("bar") runs.
The callback with console.log("foo") runs.
There isn't a message queue, there is a queue of tasks to execute. As a brief overview, the event loop takes one task from the queueand executes it to completion, then takes the next one and executes it to completion, etc. A simple pseudo-code representation would be:
while(true) {
if (eventQueue.hasNext()) {
task = eventQueue.takeNext();
task();
}
}
See here for more information on the event loop.
With all that said, the event loop has more bearing on setTimeout than many other callback-based functions. Other examples of callback based functions are jQuery's $.ajax() or the Node.js fs module for file system access (the non-promise API for it). They, and others, also take a callback that will be executed later but the bounding factor is not the event loop but whatever underlying operation the function makes. In the case of $.ajax() when the callback would be called depends on network speed, latency, and the server which responds to the request. So, while the callback will be executed by the event loop, so is everything else. So, it's hardly special. Only setTimeout has a more special interaction here, since the timings might be imprecise based on what tasks are available - if you schedule something to run in 10ms and some task takes 12ms to finish, the callback scheduled by setTimeout will not run on time.
Promise-based functions
Here is an example:
async function fn(print) {
await "magic for now";
console.log(print);
}
fn("foo")
.then(() => console.log("bar"));
/* output:
foo
bar
*/
(I'm omitting a lot of details for now for illustration.)
Promises are technically an abstraction over callbacks tailored towards handling asynchronous operations. The .then() method of a promise takes a callback and will execute it after the promise gets resolved, which also happens after the asynchronous operation finishes. Thus, we can sequence together execution in the right order:
async function fn(print) {
await "magic for now";
console.log(print);
}
fn("foo");
console.log("bar");
/* output:
bar
foo
*/
In a way, promises are sort of callbacks because they are here to replace them and do it in broadly the same fashion. You still pass callbacks to be executed when something succeeds or fails. But they aren't just callbacks.
At any rate, a callback given to a promise is still delayed:
Promise.resolve()
.then(() => console.log("foo"));
console.log("bar");
/* output:
bar
foo
*/
But not via the same event queue as the one setTimeout uses. There are two queues:
macrotasks queue - setTimeout places things in it, and all UI interactions are also added here.
microtasks queue - promises schedule their things here.
When the event loop runs, the microtasks queue (so, promises) has the highest priority, then comes the macrotask queue. This leads to:
setTimeout(() => console.log("foo")); //3 - macrotask queue
Promise.resolve()
.then(() => console.log("bar")); //2 - microtask queue
console.log("baz"); //1 - current execution
/* output:
baz
bar
foo
*/
At any rate, I don't think I'm comfortable saying that promise-based functions work via callbacks. Sort of yes but in a reductionist sense.
Asynchronous execution is non-blocking, done via event loop.
No.
What is "blocking"?
First of all, let's make this clear - blocking behaviour is when the environment is busy executing something. Usually no other code can run during that execution. Hence, further code is blocked from running.
Let's take this code as example:
setTimeout(taskForLater, 5000);
while (somethingIsNotFinished()) {
tryToFinish();
}
Here taskForLater will be scheduled to run in 5 seconds. However, the while loop will block the execution. Since no other code will run, taskForLater might run in 10 seconds time, if that's how lot it takes for the loop to finish.
Running an asynchronous function doesn't always mean it runs in parallel with the current code. The environment executes one thing at time in most cases. There is no multi-threading by default in JavaScript, parallel execution is an opt-in behaviour, for example by using workers.
What is "asynchronous execution"?
This can mean a couple of things and it's not clear which one you reference:
Running through the body of an asynchronous function
Waiting until the underlying asynchronous operation is finished
In both cases the quoted statement is wrong but for different reasons.
The body of an async function
Async functions are syntactic sugar over promises. They use the same mechanism but just present the code differently. However, an async function is blocking. As a side note, so are promise executors (the callback given to a promise constructor). In both cases, the function will run and block until something causes it to pause. The easiest way to demonstrate it is with an async function - using await will pause the execution of the function and schedule the rest of it to be finished later.
Whole body is blocking:
async function fn() {
console.log("foo");
console.log("bar");
}
fn();
console.log("baz");
/* output:
foo
bar
baz
*/
Pausing in the middle:
async function fn() {
console.log("foo");
await "you can await any value";
console.log("bar");
}
fn();
console.log("baz");
/* output:
foo
baz
bar
*/
As a point of clarification, any value can be awaited, not just promises. Awaiting a non-promise will still pause and resume the execution but since there is nothing to wait for, this will cause it to be among the first things on the microtask queue.
At any rate, executing the body of an async function might block. Depends on what the operation is.
The underlying asynchronous operation
When talking about "underlying operation", most of the times we mean that we hand off the control to something else, for example the browser or a library. In this case, the operation is not fulfilled by the current JavaScript environment we call something which will perform an operation and only notify the current JavaScript environment when it finishes. For example, in a browser calling fetch will fire off a network request but it's the browser handling it, not our code. So it's non-blocking but not by outside the execution environment.
fetch("https://official-joke-api.appspot.com/random_joke")
.then(res => res.json())
.then(joke => console.log(joke.setup + "\n" + joke.punchline));
console.log("foo");
With that said, we cannot even generalise what a given asynchronous operation will do. It might actually block the execution, at least for a while, or it might be entirely carried out in a separate process to the current JavaScript environment.
Functions like setTimeout are asynchronous.
Yes.
Although, it's probably considering what is like setTimeout. Is it setInterval? Is it any callback-based asynchronous function? The problem is that the definition starts to become circular "asynchronous callback-based functions like setTimeout are asynchronous".
Not every function that takes a callback is asynchronous. Those that are might be considered similar to setTimeout.
Asynchronous functions are blocking, only their callbacks are non-blocking.
No.
As discussed above, asynchronous functions might block. Depends on what exactly they do. For example $.ajax will initiate a network request using the browser, similar to fetch. In the case of $.ajax the function blocks while preparing the request but not after it's sent.
The second problem with the statement is that it's incorrect to call the callbacks non-blocking - executing them will certainly block the execution again. The callback is a normal JavaScript code that will be executed via the event loop when its time comes. While the task is running to completion, execution is still blocked.
If you mean that they are non-blocking in the sense that the callback will be put on the event queue, that's still not guaranteed. Consider the following illustrative code:
function myAsyncFunction(callback) {
const asyncResult = someAsynchronousNonBlockingOperation();
doStuff(result);
callback(result);
doMoreStuff(result);
}
Once someAsynchronousNonBlockingOperation() produces a value executing callback will not be scheduled for later but will be part of the synchronous sequence of code that processes that result. So, callback will be executed later but it will not be a task by itself but part of an overall task that encompasses doStuff and doMoreStuff.
Callbacks of an Asynchronous function are put in a message queue and executed via event loop.
Just in a queue (no messages). By asynchronous function I suppose you mean Promises. Remember async and await are syntactic sugar for Promises. They are execute by the event loop.
Asynchronous execution is non-blocking, done via event loop.
Not really. Javascript is single threaded: whenever it starts executing your async code, it stays there as long as needed, unless you use Workers.
Functions like setTimeout are asynchronous.
Like Promise, setTimeout and similars put the callback in a queue, which will be executed somewhere in the event loop (which may behave different for each kind of async functions).
Asynchronous functions are blocking, only their callbacks are non-blocking.
Right!

How Callback and Promise Achieve Async Property in javascript?

I have a doubt the JavaScript Is a single-threaded synchronous programming Language. and it has only One Callstack .then How the Callback and promise Achieve Asycrones property?
They don't. Callbacks and Promises do not make anything asynchronous. Instead callbacks and Promises are design patterns allowing asynchronous functions to interact with the rest of your code.
The following are two example of callbacks, one is synchronous, one is asynchronous:
function a (input, callback) {
callback(input * 2);
}
function b (input, callback) {
setTimeout(() => callback(input *2), 100);
}
console.log('start!');
a(100, x => console.log(x));
b(1000, x => console.log(x));
console.log('end!');
The output should be:
start!
200
end!
2000
Callbacks don't make anything asynchronous but is a technique of allowing asynchronous code to interact with other parts of your code.
Promises do re-schedule your .then() callback because that's the way it was designed. But all it does is execute the .then() at the end of your code. That's all it does, it does not execute the .then() callback in a separate thread.
How does it execute your code later? Well, your code is a function. It simply calls it later. How does it call it later? It simply adds your function to a list of things that needs to be done later. At the end of your code the interpreter will check this list (or lists) to see if it needs to do anything. This part of code that checks if anything needs to be executed is called the event loop. The things in the list/lists that needs to be checked are called "tasks" or "microtasks" in the documentation.
Asynchronous functions are asynchronous. They are implemented using C/C++. So if a piece of C/C++ code uses threads or signals or async I/O it can let the javascript interpreter wait for the asynchronous results using javascript callbacks (it simply accepts a javascript function that it will call later) or promises (it returns a javascript Promise object).

event emitter emit in sequence or in parallel, and behaviour when they are async

Consider the following code:
import events from 'events';
const eventEmitter = new events.EventEmitter();
eventEmitter.on('flush', (arg)=>{
let i=0;
while(i<=100000){
console.log(i, arg);
i++;
}
})
setTimeout(()=>{
eventEmitter.emit('flush', `Fourth event`);
}, 5000);
setTimeout(()=>{
eventEmitter.emit('flush', `Third event`);
}, 4000);
setTimeout(()=>{
eventEmitter.emit('flush', `First event`);
}, 2000);
setTimeout(()=>{
eventEmitter.emit('flush', `Second event`);
}, 3000);
Output1:
1 First event
2 First event
3 First event
.
.
.
1 Second event
2 Second event
3 Second event
.
.
.
1 Third event
2 Third event
3 Third event
.
.
.
1 Fourth event
2 Fourth event
3 Fourth event
What I wanted to know was, does the event that is emitted get completed first then only the second event get emitted? Or can I expect something like this:
Output2:
1 First event
1 Second event
2 Third event
3 Fourth event
3 Third event
.
.
.
What if I wrote the emitter.on function like this:
eventEmitter.on('flush', (arg)=>{
const mFunc = async ()=>{
let i=0;
while(i<=100000){
console.log(i, arg);
i++;
}
}
mFunc();
})
I was expecting output like Output2, but, instead I got something similar to Output1. Could someone please explain me this behaviour?
Also, consider this case:
eventEmitter.on('flush', (arg)=>{
const mFunc = async ()=>{
let i=0;
while(i<=100000){
console.log(i, arg);
i++;
await updateValueInDatabase(i);
}
}
mFunc();
})
Now, what would be the behaviour of the function?
Coalescing my comments into an answer and adding more commentary and explanation...
Emitting an event from an EventEmitter is 100% synchronous code. It does not go through the event loop. So, once you call .emit(), those event handlers will run until they are done before any other system events (e.g. your timers) can run.
Calling an async function is NO different from the calling point of view at all than calling a non-async function. It doesn't change anything. Now, inside an async function, you could use await and that would cause it to suspend execution and immediately return a promise, but without await, making a function async just makes it return a promise, but doesn't change anything else. So, calling the async version of mFunc() is exactly the same as if it wasn't async (except it returns a promise which you don't use). Doesn't changing sequencing of events at all.
Since you apparently thought it would change things, I'd really suggest reading a bunch more about what an async function is because your perception of what it does is apparently different than what it actually does. All async functions return a promise and catch internal exceptions which they turn into a rejected promise. If you don't use await, they just run synchronously like everything else and then return a promise.
Calling an async function returns ONLY when you hit an await or when the function finishes executing and hits a return or the implicit return at the end of the function. If there's no await, it just runs like a normal function and then returns a promise (which you aren't doing anything with). As I said above, you really need to read more about what async functions actually are. Your current understanding is apparently incorrect.
Here are some summary characteristics of an async function:
They always return a promise.
That promise is resolved with whatever value the function eventually returns with a return statement or resolved with undefined if no return statement.
They run synchronously until they either hit a return statement or an await.
At the point they hit an await, they immediately return a promise and further execution of the function is suspended until the promise that await is on is resolved.
When they suspend and return a promise, the caller receives that promise and keeps executing. The caller is not suspended unless the caller also does an await on that promise.
They also catch any synchronous exceptions or other exceptions that aren't themselves in an asynchronous callback and turn those exceptions into a rejected promise so the promise that the async function returns will be rejected with the exception as the reason.
So, if there is no await in an async function, they just run synchronously and return a promise.
In your last version of code, if you end up making your event emitter handler actually be asynchronous and actually await long enough for other things to get some cycles, then you can create some competition between timers and promises waiting to notify their listeners. The promises waiting to notify their listeners will get to run before the timers. That makes your situation of mixing those two types very complicated and very dependent upon timings. A non-ending sequence of promises waiting to notify their listeners can make timers wait until there are no more promises waiting to notify. But, if there's a moment with no promises waiting to notify, then your next timer will fire and will kick off it's own set of promise-driven operations and then all the promise-driven operations will likely interleave.
Also, emitter.emit() is not promise-aware. It doesn't pay any attention to the return value from the callbacks that are listening for the emit. So, it doesn't make any difference at all to emitter.emit() whether the listeners are async or not. As soon as they return (whether they returned a promise or not), it just goes right on to whatever it was going to do next. Promises only influence code flow if the recipient uses them with await or .then() and .catch(). In this case, the recipient does nothing with the return value so emitter.emit() just goes right onto its next order of business and executes that.
okay, so, if I have a bunch of async function arrays [async1, async2, async3, ....], and they all have await statements internally, what would be the best way to execute them in sequential order? i.e. one after other in order of their index?
Well, if you had an array of async functions that properly resolve their promise when they are actually done with their work, you can execute them sequentially by just looping through the array with an await.
async function someFunc() {
const jobs = [asyncFn1, asyncFn2, asyncFn3];
for (let job of jobs) {
let result = await job(...);
}
}
Internally, the EvenEmitter hold an array of listeners for each event type. When you emit an event type, the EvenEmitter just goes through it's array of listeners and execute it. Therefore, the listeners are executed in the order it was added by addListener or on method.
To answer your questions there are two parts: a) it executes in the order you added the listener and b) it depends if the listeners are async or not. If your listeners are synchronous, then you can expect that behavior. If your listeners are async, you can't expect that. Even if your execute your async synchronously, they will not necessarily resolve at the same time because it's the nature of being async.

How does RxJS create or simulate asynchronism?

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.

Categories

Resources