Are Observables Asynchronous?

Share on facebook
Share on google
Share on twitter
Share on linkedin

A common misconception in Angular development is regarding whether observables are synchronous or asynchronous. A lot of (even experienced Angular developers) think that observables are async, but the truth is that they can be…

Both synchronous and asynchronous.

To understand why this is, let’s define what it actually means to run code async in the browser.

When is code running asynchronously in the browser?

To explain when code is running asynchronously in the browser let’s consider how the event loop works. The event loop is initiated by running some functions from the stack. Allocated memory is created on the heap as the stack instructs eg. to instantiate objects. The stack can also contain instructions to execute asynchronous browser API functions. These are eg. XMLHttpRequest, setTimeout, interval and dom event and executing any of these functions will run code asynchronously in Javascript.

Now, when any of these asynchronous browser API functions are being called, the execution is scheduled on a task queue (either macro or micro task queue). The a task queue is being emptied only when the stack is empty. This can be illustrated with these steps:

Credit Philip Roberts – https://www.youtube.com/watch?v=8aGhZQkoFbQ

 

This is how the event loop works:

1)  Run functions from the stack

2) Call async browser API function

3) Add them to the task queue (either micro or macro task queue – more on this soon)

4) Empty stack/execute all pending operations on the stack

5) Move a task from a task queue to the stack

6) Execute the task on the stack (stack becomes empty again)

7) Repeat step 5-6 until the task queue is empty

 

For a more in-depth description of how the event-loop works I recommend you to check out this video: https://www.youtube.com/watch?v=8aGhZQkoFbQ

Nevertheless, this is all we need to know for this blog post. Let’s not make things too complicated here.

 

Macrotasks and microtasks

I don’t intend to bore you with any more of the low-level browser details but understanding these concepts will help you distinguish the different kinds of async tasks, that can be run. The ones we just explored were the macro tasks. Other kinds of async tasks are micro tasks which happen when promises are used.

In the previous description of the event loop, the task queue we were talking about was the macro task queue, ie. task queue for callbacks from eg. DOM, XMLHttpRequest, and setTimeout.

Micro and macro tasks have separate queues and work almost the same way. The difference is that the micro task queue has a higher priority than the macro task queue. That means that when using promises in the event loop, the promise callbacks will execute before the macrotasks and the macrotasks will only be executed when the microtask queue is completely emptied.

Both macrotasks and microtasks are considered asynchronous, so using either of them in an Observable stream will per definition make the stream asynchronous.

The execution order can be visualized like this:

RxJs schedulers

This answer wouldn’t be complete if I didn’t also touch on the Schedulers in RxJS. The schedulers in RxJS can determine if an observable is run synchronously, on the macro task queue or on the microtask queue.

Let’s see a demo of how the different schedulers can be used to determine the execution of observables

Also, note that the animation frame scheduler is used here, which will run when the browser repaints and is triggered when requestAnimationFrame from the browser API is fired.

This gives the results:

This shows that queue is running synchronously as it is triggered before the other synchronous “after subscription” console log.

After this comes the asynchronous schedules observables. The asap scheduler runs next because it runs as a micro task, then the animation frame scheduler and then lastly the async because it runs as a macro task.

Observables: async or sync shouldn’t change the design

Now we know that observables in itself are synchronous (at least with the synchronous scheduler) as they are just registered callbacks to be executed on the stack. Remember stack only = synchronous.

What makes observables smart is the same reason this confusion came up in the first place: it is designed to be used the same way regardless if it is synchronous or asynchronous. That means you don’t need to worry about timing problems and handling state in a specific order as you just subscribe to the stream and that will give you the data when it is ready. The subscribe callback can be triggered right away if it is synchronous or delayed if it is asynchronous.

Cool story, how can I apply this knowledge?

If you are a regular reader of my blog, you know I don’t just drop buzzwords and “interesting” knowledge without it being valuable in specific practical scenarios.

You can apply this knowledge by knowing the execution order of observables. Especially when writing unit tests involving an observable, you would normally stub out all the dependencies making the observable execute synchronously. Here you can trust that a subscribe will be executed before the code underneath.

Note, that if you are doing asserts inside of a subscribe, you need to also call the done callback in the test. Otherwise, you could risk the subscribe callback never being called and the tests would still show as passed, giving you a false positive.

Conclusion

In this post, we saw that observables can by definition both be synchronous and asynchronous because it is determined whether the asynchronous browser API functions are being executed. We also looked at how the event loop works, what the difference is between macrotasks and microtasks and how to apply all of this in RxJS with schedulers.

 

Do you want to become an Angular architect? Check out Angular Architect Accelerator.

Related Posts and Comments

Refactoring Angular Apps to Reactive Architecture

As an Angular consultant, the main problem I see new Angular developers have is how to use RxJS efficiently in Angular apps. In other words, how to use it to create a scalable and maintainable reactive architecture. What I see instead is an abuse of RxJS, which is a completely natural thing to do, when

Read More »

The Ten Commandments of Angular Development

As a consultant, I normally work with companies between 3-12 months at a time and then I am off to the next gig. Most often, I am hired as a “hands-on” coach, were I am called in for an important and urgent project to make stuff happen within a very tight deadline. This requires that

Read More »

The Complete Guide to NgRx Testing (2020)

The main secret behind having better test coverage in an Angular app is to reduce the friction it takes to write tests and enforce test coverage by setting a test coverage threshold to be checked on every commit. NgRx and reactive testing is an area where many people get confused because it seems hard to write

Read More »

How to do Tree Searching with Javascript

A common question for job interviews is searching in trees and therefore you should always be prepared to solve this with ease. As always then solving a problem you want to solve it conceptually before writing the actual code. This is done by going through the logical steps needed to get the desired outcome for

Read More »

4 thoughts on “Are Observables Asynchronous?”

  1. Тетяна

    Hi Christian!
    Thank you for so easy to understand article.
    Could you please give an example when

    if you are doing asserts inside of a subscribe … you will get the subscribe callback never being called

    using RxJS.of ? Seems to me that RxJS.of without second arg is always synchronous.
    Looking forward to your answer.

    1. I was thinking the same thing. If the observable is synchronous you don’t need to call `done` – I write a lot of unit tests like this

  2. It’s the first time I read about the micro and macro schedulers. The example is very informative. I ended up here in search of a solution to my issue of updating a behavior subject with a next() function call from within a long running expensive service.

Leave a Comment

Your email address will not be published. Required fields are marked *