Angular Js

Observables OR Promises, Which One Should You Use

Observables OR Promises, Which One Should You Use

Observable OR Promises, Which One Should You Use?

This Article helps you to Understand, Observable OR Promises, Which One Should You Use?


JavaScript is an asynchronous, concurrent, single-threaded, and non-blocking language. This indicates that the JavaScript engine doesn't wait around for statements to complete. Instead, it advances to the subsequent assertion.

How reliable are the outputs of asynchronous functions then? Callbacks were the sole solution in the beginning. They did, however, make the code difficult to comprehend, which resulted in the infamous callback hell.

To specifically address that issue, Observables and Promises were created.  Promises and Observables have a completely different approach to dealing with async code. Their implementations make it easier for us to handle that asynchronous code. But, how can we choose the one that is best for us? Here, we'll compare each implementation's differences.


1. Single value vs. multiple values
The primary distinction is that once Promises are fulfilled, they retain their original value and won't change it. Only one value can be emitted (either rejected or resolved) by them.
Observables, on the other hand, can emit multiple results. Until the observer is finished or the subscription unsubscribes, the subscriber will continue to get results. To demonstrate these changes, here is some code:


// Promises
const x = new Promise((resolve) => {
  setInterval(() => {

      //The promise will be fulfilled when resolve is called, and its value will never change.
      resolve(Math.random() * 10)
  }, 3000);
});



// Observables
const observable$ = rxjs.Observable.create((observer) => {
   // you can pass multiple values by using `next` method
   observer.next(1);
   observer.next(2);
   observer.next(3);
   observer.complete();
})

// subscribers will continue to receive values till it is finished.
observable$
  .subscribe(
    v => console.log(v),
    err => console.log(err),
    done => console.log("completed")
  );


Because of this, Observables make an excellent tool for monitoring data streams. Even subjects are a type of bidirectional observable. Web sockets are the ideal use case for such.


2. Promises cannot be cancelled, but observable subscriptions may.

A promise that has been started cannot be stopped. Resolving or rejecting the promise will be handled by the callback that was supplied to the Promise constructor. The subscriber is unresponsive; after being fired, it can only respond to the outcome.

Less passive are observables. Once a subscriber is established, it is always free to leave the observer. Because of this, they are helpful in situations where the reaction ore response is no longer important for subscriber. As in the case of a user leaving a page.

Observers has many ways to cancel/complete subscribers like:-

unsubscribe: manually terminating the Observable's subscription
take: allow operator to cancelling the subscription after using X components and after X numbers.
takeUntil: an operator that continues to take values until the passed Observable emits a value.


// Cancelling by using the unsubscribe method
const observable1$ = rxjs.interval(1000);
const subscription1$ = observable1$
  .subscribe(x => console.log(x));

subscription1$.unsubscribe();



// Cancelling by taking a number of elements
const observable2$ = rxjs.interval(1000);
observable2$
  .pipe(rxjs.operators.take(5))
  .subscribe(x => console.log(x));



// Conditionally stop listing for more elements
const subject3$ = new rxjs.Subject();
const observable3$ = rxjs.interval(1000);

observable3$
  .pipe(rxjs.operators.takeUntil(subject3$))
  .subscribe(x => {
    console.log(x);
    if (Math.random() > 0.5) {
      subject3$.next(1);
      subject3$.complete();
      console.log('complete');
    }
  });
 



3. Eager vs. lazy execution

Promises and Observables are executed in different ways. Promises are carried out eagerly whereas Observables are carried out lazily. Why does that matter?

Eagar: The Promise callback will execute right away at the constructor level.
Lazy: Only after a subscription has been created for that Observable will the Producer function be activated. If not, it will remain inactive.


A Promise

const message = new Promise((resolve) => {
  console.log('1. Callback execution');
  resolve(true);
});

message.then(() => {
  console.log('2. Promise resolution');
});

console.log('3. Pre exit method statement');


console output
// 1. Callback execution
// 3. Pre exit method statement
// 2. Promise resolution



An Observable

const observable$ = new rxjs.Observable(observer => {
  console.log('1. Execution of observable body');
  observer.next(1);
  observer.complete();
});

console.log('2. Pre Subscribe statement');

observable$.subscribe(() => {
  console.log('3. Execution of subscribe callback')
});

console output
// 2. Pre Subscribe statement
// 1. Execution of observable body
// 3. Execution of subscribe callback




4. Runtime execution

Once the Promises are fulfilled, the callback will be placed in the microtask queue. That indicates that they will be carried out following the conclusion of the current macro task.


console.log('1. Start');

setTimeout(() => {
    console.log('2. Timeout callback')
}, 0);

Promise.resolve().then(() => {
    console.log('3. Promise callback')
});

console.log('4. End');

outputs
// 1. Start
// 4. End
// 3. Promise callback
// 2. Timeout callback


The aforementioned behaviour cannot be altered.


Utilizing schedulers, you can modify the runtime execution of Observables. When a subscription begins and when notifications are sent out are both controlled by a scheduler.

Null: Recursive and synchronous delivery of notifications is the default.
queueScheduler: recursively schedules tasks in the current event frame.
asapScheduler: using the microtask queue to schedule. same queue as is used for promises.
asyncScheduler: like setting up a job with setInterval. As a result, it will be planned in the macro task queue.
animationFrameScheduler: relies on requestAnimationFrame API.


const observable1$ = rxjs.interval(1000)
  // ✅ using the asapScheduler scheduler
  .pipe(rxjs.operators.observeOn(rxjs.asapScheduler));

const subscription1$ = observable1$
  .subscribe(x => console.log(x));




Can they work together despite having a lot of disparities between them?

You can create Observables from promises and you can dump an Observable to a Promise. However, in the latter, as Promises take only one value, you would have to choose if you want the first or last value to be dumped to the Promise.


// Observable -> Promise
const source$ = rxjs.interval(2000).pipe(rxjs.operators.take(10));
// toPromise is deprecated in favor of firstValueFrom and lastValueFrom
// outputs 9
const result = await source$.toPromise();



// Promise -> Observable
const promise = Promise.resolve(10);
rxjs.from(promise)
  // outputs 10
  .subscribe(item => console.log(item));




Related Post

About Us

Community of IT Professionals

A Complete IT knowledgebase for any kind of Software Language, Development, Programming, Coding, Designing, Networking, Hardware and Digital Marketing.

Instagram