Difference between Promises and Observables
Tags: javascript, typescript, webdev, programming
Published: 2023-02-11 19:09:03

Imagine that you have a friend who promises to give you a toy. A promise is like that - it's when someone says they'll do something for you in the future. So when your friend promises to give you a toy, you trust that they will do it.

Now, imagine that you're waiting for your friend to bring you the toy, but you don't know when they'll arrive. This is kind of like an observable. An observable is like waiting for something to happen, but you don't know exactly when it will happen. It's like watching a caterpillar turn into a butterfly - you know it will happen, but you don't know exactly when.

In computer programming, promises and observables are used to help us do things in a certain order. For example, we might use a promise to wait for data to be loaded from a website, and then use an observable to show that data on the screen. Just like waiting for your friend to bring you a toy, promises and observables help us trust that certain things will happen in the right order.

Promises and observables are both design patterns used for handling asynchronous operations. However, they are different in their implementation and use cases.

## Promise

A Promise is a single-value container that represents the eventual result of an asynchronous operation. Once a promise is resolved or rejected, its value can not change anymore. It is often used when you want to handle the result of an async operation, like an HTTP call. Promises are commonly used to handle async operations that return a single result.

A promise represents a value that may not be available yet. It's a returned object to which you attach callbacks, instead of passing callbacks into a function. A Promise has two states: "pending" and "settled". A promise is said to be "pending" when it has not yet been fulfilled or rejected. A promise is said to be "settled" when it has either been fulfilled with a value or rejected with a reason (error).

Here's an example of using a Promise to handle an asynchronous operation:

``` js
function getData(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
}

getData('https://jsonplaceholder.typicode.com/posts')
  .then((data) => {
    console.log(data);
  })
  .catch((error) => {
    console.error(error);
  });
```

In this example, we use the `getData` function to make an HTTP `GET` request to a URL and retrieve the response text. The `getData` function returns a `Promise` that is resolved with the response text when the request is successful, or rejected with an error message when the request fails. The Promise is used by calling the then method and passing in a success callback, as well as a `catch` method to handle any errors.


## Observable

An Observable is a sequence of values that can be observed over time. It's like a stream that can emit multiple values over time, and it can be used for handling asynchronous data such as events or data from an API. An Observable can be "subscribed" to and whenever a new value is emitted, the subscriber will receive it.

An Observable is a stream of values over time. An observable can emit multiple values over a period of time, and you can subscribe to it to receive each value as it comes in. It is similar to a promise but it is a representation of a series of future values or events. Observables are more versatile and can be used for handling more complex async operations, like real-time updates, user input, and handling multiple values over time.

Here's an example of using an Observable to handle an asynchronous operation:

``` js
import { Observable, fromEvent } from "rxjs";

const button = document.querySelector("button");
const clickObservable = fromEvent(button, "click");

clickObservable.subscribe((event) => console.log(event));
```

In this example, we use the `fromEvent` function from the `rxjs` library to create an Observable that represents a stream of button click events. We then `subscribe` to the `Observable` using the `subscribe` method, and whenever the button is clicked, the `subscriber` will receive the `event`.

Choosing between a Promise and an Observable will depend on the specific requirements of your application. If you need to handle a single asynchronous result, then a Promise is probably the better option. However, if you need to handle multiple values over time, or if you want to be able to cancel an ongoing operation, then an Observable would be a better choice.


## Difference Table

| Feature | Promise | Observable |
| --------- |:---------:| -------:|
| Representation | Single-value container | Stream of values over time |
| Number of Values | Single-value container | Multiple values over time |
| Use Case | Ideal for handling a single result of an async operation | Ideal for handling multiple values over time, like real-time updates, user input, etc. |
| Immutability | Value cannot be changed once it is resolved or rejected | Observables can change values over time |
| Syntax | Simpler syntax | More complex syntax |
| Error Handling | Reject callback for error handling | Error handling through catch and/or onError callbacks |
| Chaining | Can chain multiple then callbacks | Can chain multiple subscribers |
| Lazy Evaluation | Evaluates immediately | Can be lazily evaluated by subscribing |
| Composability | Difficult to compose Promises | Easy to compose and manipulate Observables using operators |
| Cancellation | No built-in support for cancellation | Supports cancellation through unsubscribing |
| Blocking | Blocking - waits for the result | Non-blocking - emits values as they come in |
| Creation | <code> const promise = new Promise(() => { <br> resolve(10); <br> }); </code> | <code> const obs = new Observable((observer) => { <br> observer.next(10); <br> }); </code> |
| Transform | <code> promise.then((value) => value * 2); </code> | <code> Obs.pipe(map(value) => value * 2); </code> |
| Subscribe | <code> promise.then((value) => { <br> console.log(value); <br> }); </code> | <code> const sub = obs.subscribe((value) => { <br> console.log(value); <br> }); </code> |
| Unsubscribe | Can’t unsubscribe | <code> sub.unsubscribe(); </code> |


## When we should use

Promises and Observables are used in different situations, depending on the nature of the asynchronous operation you're trying to perform.

Promises are typically used when you have a single asynchronous operation that needs to be performed, and you want to be notified when that operation has completed (or if it fails). For example, you might use a Promise when you need to make an HTTP request to retrieve data from a server, and you want to handle the response when it arrives.

Observables, on the other hand, are typically used when you have a sequence of asynchronous events that you want to observe over time. For example, you might use an Observable when you want to subscribe to a stream of mouse clicks or keyboard events, and you want to handle each event as it occurs.

In general, if you have a single asynchronous operation that you want to perform, and you just want to be notified when it has completed, a Promise is a good choice. If you have a sequence of events that you want to observe over time, an Observable is a good choice.

Ultimately, the choice between a Promise and an Observable will depend on the specific requirements of your application, and it's important to understand the differences between the two concepts in order to make the right choice for your use case.


## When we should not use

We should not use Promises or Observables in situations where they are not appropriate. Here are a few examples of when you might want to avoid using either one:

- Avoid using Promises when you need to observe a stream of events over time, rather than a single value that may or may not be available. In this case, an Observable is a better choice.
- Avoid using Observables when you have a single asynchronous operation that you just need to perform, and you don't care about observing the results over time. In this case, a Promise is a better choice.
- Avoid using Promises or Observables when you can perform the operation synchronously, without involving any asynchronous behavior. In this case, using a synchronous solution is a better choice.
- Avoid using either Promises or Observables in situations where you need tight control over the order in which events occur. For example, if you need to perform a set of operations in a specific order, and you need to guarantee that one operation is complete before starting the next, you might want to avoid using either Promises or Observables, and instead use a more traditional approach like callbacks or chaining Promises.

Ultimately, the choice between a Promise and an Observable, or whether to use either one at all, will depend on the specific requirements of your application. It's important to understand the strengths and weaknesses of each concept, in order to make the right choice for your use case.


## Conclusion

Promises and Observables are two powerful concepts in JavaScript and TypeScript for handling asynchronous operations. Promises are used for representing a single asynchronous operation, where you just want to be notified when the operation is complete or has failed. Observables, on the other hand, are used for representing a sequence of asynchronous events, where you want to observe each event as it occurs over time.

When choosing between Promises and Observables, it's important to consider the nature of the asynchronous operation you want to perform, and the requirements of your application. If you have a single asynchronous operation that you just need to perform, and you don't care about observing the results over time, a Promise is a good choice. If you have a sequence of events that you want to observe over time, an Observable is a good choice.

In any case, it's important to understand the differences between Promises and Observables, and to make the right choice for your use case in order to write efficient, maintainable, and scalable code.