Deciphering the outcomes of Promise versus Observables

Query:

Methodology

  fetchDataQuery(): any {
    let query = new Query((resolve, reject) => {
      resolve([
        { name: 'Apple', type: 'fruit' },
        { name: 'Banana', type: 'fruit' }
      ]);
    });
    return query;
  }

// query execution
fetchDataQuery.then((data) => { 
    console.log("Obtained data: ", data);
});

Data is in an Array format:

Data: [
  { name: 'Apple', type: 'fruit' },
  { name: 'Banana', type: 'fruit' }
]

Inquisitive

Procedure

  import { from } from 'rxjs';

  fetchObservableData(): any {
    return from([
      { name: 'Apple', type: 'fruit' },
      { name: 'Banana', type: 'fruit' }
    ]);
  }

// observable retrieval
fetchObservableData().subscribe((data) => {
    console.log("Resulting output: ", data);
});

Data consists of 2 objects sequentially:

Data: { name: 'Apple', type: 'fruit' }
Data: { name: 'Banana', type: 'fruit' }

Attempted to grasp the distinction, reviewed online resources yet still cannot address the following 2 inquiries.

  • Why does the output vary?

  • What's the approach to retrieve the outcome from the observable as an array (similar to promise)?

Answer №1

When a promise concludes, it either resolves (then) or rejects (catch). On the contrary, an observable continues to stream values until it terminates (sometimes persisting indefinitely, only ceasing when interest is lost - or unsubscribed from).

An interesting analogy can be drawn using keypress events. Using a promise for resolving/rejecting based on a keypress will only capture the "next" keypress event, requiring creation of a new promise for subsequent events.

On the other hand, with observables, creating just one instance allows continuous streaming of values until disinterest prompts unsubscription.

Promises:

const subscribeToKeyPress = () => {
  let resolve;
  document.addEventListener('keydown',function listener(e) {
      resolve(e);
      document.removeEventListener('keydown',listener); // prevent memory leaks
  });
  return new Promise(r => resolve = r);
}

subscribeToKeyPress().then(e => {
  // completed, no further results expected
});

#####
Observables:

const subscribeToKeyPress$ = () => fromEvent(document,'keypress);

const unsubscribe = subscribeToKeyPress$().subscribe(e => {
  // continuously triggered by each keypress until unsubscribed
});

unsubscribe(); // stops callback execution, avoiding memory leaks

#####
Callback Function - a basic form of "observable"

const subscribeToKeyPress = callback => {
   const fn = e => callback(e); // repeated execution until unsubscribed
   document.addEventListener('keypress',fn);
   return () => document.removeEventListener('keypress',fn);
}

const unsubscribe = subscribeToKeyPress(e => {
  // repeatedly invoked on every keypress unless unsubscribed
});

unsubscribe(); // prevents further callback calls to avoid memory leaks

How do you obtain the result from an observable as an array (similar to a promise)?

Visit https://www.learnrxjs.io/operators/utility/topromise.html for insights.

Additional information about toPromise: https://github.com/ReactiveX/rxjs/issues/2539

If your observable never reaches completion (e.g., a keypress listener), utilizing toPromise might not function effectively (consider pipe(take(1)) beforehand, but this complexity may overwhelm newcomers. Coming from a promise-centric background, grasping observables can pose challenges initially, though they eventually become more comprehensible with time and practice.

Answer №2

When dealing with asynchronous tasks, both promises and observables require proper handling.

The from operator treats arrays as a sequence of values, leading to the displayed results.

According to the documentation, using the from operator:

Turns an array, promise, or iterable into an observable.

This explains why getDataObservable presents the objects as separate sequences.

To merge them into a single sequence, consider using the of operator instead.

Emits variable amounts of values in a sequence followed by a complete notification.

import { of } from 'rxjs';

const getDataObservable = () => {
  return of([
    { brand: 'iPhone', model: 'Xmax', price: '$1000' },
    { brand: 'Samsung', model: 'S10', price: '$850' }
  ]);
}

getDataObservable().subscribe((data) => {
    console.log("Result: ", data);
});

Check out this demo.

Answer №3

It's important to remember that using from will result in all values from arrays and iterables being emitted as a sequence.

This means that if you have an array like this:

from([[
  { brand: 'iPhone', model: 'Xmax', price: '$1000' },
  { brand: 'Samsung', model: 'S10', price: '$850' }
]]);

You will get the same result as before.

The distinction between observable and promise:

There is a key difference between observables and promises:

  1. If you subscribe to an observable after the event has already occurred, you won't receive notifications for past events (only for future ones). However, with a promise, the then() method will still be effective.
  2. With an observable, you can continue to receive notifications for the same type of event multiple times. On the other hand, once a promise is settled (resolved or rejected), it is completed and cannot be triggered again.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Theme not being rendered properly following the generation of a dynamic component in Angular

I am currently working on an Angular 9 application and I have successfully implemented a print functionality by creating components dynamically. However, I have encountered an issue where the CSS properties defined in the print-report.component.scss file a ...

Issue with ellipsis not functioning correctly on dynamic placeholders when they are in focus

When I focus on my dynamic placeholder input, the text-overflow: ellipsis property is lost for some reason. However, it is regained when blurred. Can anyone explain why this is happening? If you want to experiment with it, I have set up a stackblitz: htt ...

Issue with obtaining access token in Angular 8 authentication flow with Code Flow

As I work on implementing SSO login in my code, I encounter a recurring issue. Within my app.module.ts, there is an auth.service provided inside an app initializer. Upon hitting the necessary service and capturing the code from the URL, I proceed to send a ...

The CommonsChunkPlugin in Webpack and leveraging the "import * as" syntax

I've been studying Webpack for a while now and recently encountered an unusual issue. According to the Webpack Introduction on angular.io, I organize my vendor modules in the vendor.ts file, polyfills in the polyfill.ts file, and initialize my app in ...

Navigating through different routes in an Angular application can be tricky, especially when dealing

I am facing an issue with the navigation links in my sidebar, which are located within a child module named "login". When I click on "Classroom", it correctly directs me to "login/classroom". However, when I click on "Assignments", it appends "assignment ...

The Typescript Decorator is triggered two times

I submitted a bug report regarding Typescript because I suspect there is an issue, although I'm seeking additional insights here as well. This is the scenario. When running the following code: class Person { @IsValueIn(['PETER', ' ...

Activate a function with one event that is triggered by another event in Angular 5 and Material Design 2

I am facing an issue where I need to change the value of a radio button based on another radio button selection in Angular 5 with Material Design 2. However, the event is not triggering and there are no console errors being displayed. For example, if I cl ...

"Exploring the process of implementing a fixed method POST in Angular 5

When developing an application for Portal, I encountered an issue where a newly created role is not displayed without refreshing the browser. How can I ensure that the added element is directly displayed in the table without needing to refresh the browser? ...

trouble with the layout of the table

Could you assist me in improving the design to enhance data clarity? Your help would be greatly appreciated. Thank you for your anticipated response. CSS File: table-layout: fixed; width: 100%; border-collapse: collapse; table-layout: fixed; ove ...

How can an Angular property decorator enhance the lifecycle hooks of a component?

Utilizing the given code snippet, I am able to include a @Test() to my component. However, my requirement is to append a command to the ngOnInit hook without replacing it completely within the component. function Test(value:any) { return function(targe ...

I am encountering an issue where Typescript paths specified in the tsConfig.app.json file are not resolving properly

I have defined path settings in my tsconfig.app.json file like this: "paths": { "@app/core": ["./src/app/core"] } Every time I run a test that includes import statements with relative paths, it throws the following error: ...

A step-by-step guide to resolving the TS2345 compilation error during your TypeScript upgrade from version 4.7 to 4.8

We encountered a compiling error after upgrading from TypeScript 4.7.4 to a newer version (specifically, 4.8.4). This error was not present in our codebase when using 4.7.4. To pinpoint the issue, I have extracted the error into a small code snippet. When ...

The system does not acknowledge 'NODE_OPTIONS' as a command that can be used internally or externally, or as an operational program or batch file

While trying to build my react + vite project, I encountered an error after running npm run build. https://i.stack.imgur.com/XfeBe.png Here is a snapshot of my package.json file. https://i.stack.imgur.com/MbbmY.png ...

What impact does the deprecation of TSLint have on Angular projects?

At the company I currently work for, we are on the cusp of embarking on a new Angular application project. Delving into the topic of linting, I came across news that TSLint is in the process of being deprecated. Given that TSLint is integrated into Angula ...

Using gulp to compile TypeScript is resulting in a directory being generated that we do not want

My goal is to use Gulp to transpile my .ts files located in the /dev directory, and then move the transpiled .js file to a /build directory. The ideal folder structure I am aiming for is as follows: /dev - index.ts /build - index.js However, the curre ...

Even when imperfections inevitably arise, flawless submission is always achieved

When working with a form that has a set minimum and maximum number of characters, I encounter an issue. If the minimum is set to 2 characters and I only input one character, I receive a mat-error message. However, upon clicking save, it allows me to procee ...

Showcasing diverse content with an Angular Dropdown Menu

I'm currently developing an angular application, and I've encountered a difficulty in displaying the user's selection from a dropdown menu. To elaborate, when a user selects a state like Texas, I want to show information such as the period, ...

Oops! Looks like there's an unexpected error with the module 'AppRoutingModule' that was declared in the 'AppModule'. Make sure to add a @Pipe/@Directive/@Component annotation

I am trying to create a ticket, but I encountered an error. I am currently stuck in this situation and receiving the following error message: Uncaught Error: Unexpected module 'AppRoutingModule' declared by the module 'AppModule'. Plea ...

Is it possible to define a multiplication margin using css?

I am trying to place a box in the center of a container, but I am unable to set a static height for the parent element as it may change. This is causing issues with aligning the box perfectly in the middle of the page. Any assistance would be greatly app ...

Exploring the typing for DefaultRootState in React Redux Connect

I'm currently in the process of upgrading to the latest versions of TypeScript, React, and Redux. However, I've encountered a compiler error when using the connect function in React Redux: According to the React Redux documentation, I typed my r ...