In what way can a piped operator in rxjs be influenced by the value returned by a subsequent operator?

When attempting to examine values between operators in an rxjs pipe, I decided to use tap to log them to the console.

I added two taps, one before a map operator used for sorting an Array, and one after. Surprisingly, both taps logged the same sorted Array, instead of displaying the original order followed by the sorted one.

This indicates that the sorting done in the map operator impacts the observable used by the preceding tap operator. However, the operators' functions appear to execute sequentially as expected, since the log from the second map is displayed between the taps' logs.

Here is my code (I plan to specify the Observable Array's type properly later):

public getJSONData(): Observable<any[]> {
    return this.http.get(this.poisJSONPath).pipe(
      map((featureCollection: any) => featureCollection.features),
      tap((features) => console.log(features)),
      map((features: any) => {
        console.log('this is logged in between as expected');
        return features.sort((a, b) =>
          a.properties.name > b.properties.name ? 1 : -1
        );
      }),
      tap((features) => console.log(features))
    );
  }

I suspect there may be a critical aspect of how rxjs pipes operate that I'm overlooking. In every other example I've seen, tap behaves as I anticipate. Can anyone point out what I might be missing?

Answer №1

The most straightforward explanation is that the array is already organized.


Upon closer inspection, when I execute this code:

of({
  features: [3,4,7,1,3,8]
}).pipe(
  pluck('features'),
  tap(console.log),
  map(features => {
    console.log('this is logged in between as expected');
    return features.sort(
      (a, b) => a > b ? 1 : -1
    );
  }),
  tap(console.log)
).subscribe(console.log);

This is what I see in the output:

[3,4,7,1,3,8]
this is logged in between as expected
[1,3,3,4,7,8]
[1,3,3,4,7,8]

Therefore, it could be related to the environment where you are running the code.

If, for instance, console.log is buffered, then maybe the array has been altered in memory before it's actually printed, even though the order of printing remains intact.


An Important Point

RxJS does not provide any assurances about the state of memory. Hence, it is advisable to use pure, non-mutating functions so that your program logic becomes easier to understand.

Take into account this example:

const delayedLog = val => setTimeout(() => console.log(val), 1000);

of({a: 5}).pipe(
  tap(delayedLog),
  map(input => {
    delayedLog("this is logged in between as expected");
    input.a++;
    return input;
  }),
).subscribe(delayedLog);

output:

{"a":6}
this is logged in between as expected
{"a":6}

The value {"a":6} is printed two times although initially a = 5 when the first delayed log is triggered. This happens because the value changes in memory prior to the console reading the value from memory.

Vs

const delayedLog = val => setTimeout(() => console.log(val), 1000);

of({a: 5}).pipe(
  tap(delayedLog),
  map(input => {
    delayedLog("this is logged in between as expected");
    return { a: input.a + 1 }
  }),
).subscribe(delayedLog);
{"a":5}
this is logged in between as expected
{"a":6}

In this case, we obtain the anticipated result since we do not alter the object directly; instead, we return a new object with the incremented value.


A Starting Point for Investigation

Try sorting a copy of the array and check if that resolves the issue for you.

public getJSONData(): Observable<any[]> {
  return this.http.get(this.poisJSONPath).pipe(
    pluck('features'),
    tap(console.log),
    map((features: any[]) => {
      console.log('this is logged in between as expected');
      return [...features].sort((a, b) =>
        a.properties.name > b.properties.name ? 1 : -1
      );
    }),
    tap(console.log)
  );
}

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

Leveraging RXJS for efficient data retrieval in nodejs

When dealing with sending a bulk of data and moving on to the next one upon completion, it can be quite challenging. Take for instance this function: async function test() { await sample.sampleStructure() await sample.sampleDataAdd() await sample.sa ...

Angular2's counterpart to the angular.version property in AngularJS

If you open the browser's developer console (you can press F12), and type in "angular.version", it will display the version of AngularJS APP that is currently loaded on the page. Is there a similar command for finding out the version of Angular2? ...

Is there a way to pass around jest mocks across numerous tests?

In my test scenarios, I've created a mock version of the aws-sdk, which is functioning perfectly: jest.mock("aws-sdk", () => { return { Credentials: jest.fn().mockImplementation(() => ({})), Config: jest.fn().mockImplementati ...

Which option is more beneficial for intercepting API data in Angular 6: interfaces or classes?

My API returns JSON data that is not structured the way I need it, so I have to make changes. { "@odata.context":"xxxxxx", "id":"xxxxxxxx", "businessPhones":[ ], "displayName":"name", "givenName":"pseudo", "jobTitle":null, "ma ...

Fetching User Details Including Cart Content Upon User Login

After successfully creating my e-commerce application, I have managed to implement API registration and login functionalities which are working perfectly in terms of requesting and receiving responses. Additionally, I have integrated APIs for various produ ...

What is the best way to utilize Object.keys() for working with nested objects?

When working with nested objects, I am trying to access the properties using Object.keys() and forEach(). However, I am encountering an issue when attempting to access the nested keys filteringState[item][el]. Is there a specific way to write a function f ...

Encountering a runtime issue with socket.io when using typescript that has been bundled by

Recently, I attempted to implement web sockets using socket.io in a Node server written in TypeScript with ExpressJS and bundled with Webpack. The server code is structured as follows: import * as Express from "express"; import * as SocketIO from "socket ...

Check for a rapid return if the function ends up returning null in JavaScript

Is there a way to make this code more concise? const result = getResult(); if (!result) { return; } // Work with result I have several instances of this code in my project and I'm looking for a simpler solution like: const result = getResult() ...

Angular - Facing issues with CORS for every request made

Currently, I am developing an angular 12 application for my university with a java back-end. While testing Angular's http client, I encountered an issue where CORS is blocking my requests. const API_URL = 'http://localhost:9080' @Injectable ...

Learn how to access tag attributes within the ngIf function in Angular 2

considering this structure <a *ngIf="canAccess()" routerLink="/adminUsers">...</a> <a *ngIf="canAccess()" routerLink="/link2">...</a> <a *ngIf="canAccess()" routerLink="/otherlink">...</a> <a *ngIf="canAccess()" rout ...

The recent update to Bootstrap v5 caused a complete disruption in the CSS of our application

My Angular app was originally on Angular 14 and used Bootstrap with SCSS compiled to node-sass/SASS package. It also utilized ng-bootstrap v11 and Bootstrap v4.3.1 for CSS styles. As part of a general upgrade, I needed to update the Angular version to 15. ...

The properties 'paginator' and 'sort' are missing an initial value

Struggling to implement a form filter similar to the one shown on a specific website, I encountered some code issues in my own environment. Check out this data table example with sorting, pagination, and filtering. @ViewChild(MatPaginator) paginator: MatP ...

Unable to exclude modules from ng-build in Angular CLI, the feature is not functioning as intended

I am managing an Angular CLI project that consists of two identical apps. However, one app requires the exclusion of a specific module in its build process. Key Details: Angular CLI Version: 1.7.4 Angular Version: 5.2.10 In the angular-cli.json ...

Ways to retrieve the following angular.callbacks.counter within angular2

In order to use the Yelp API, a signature is required. This signature needs to be generated by passing all the parameters for the URL that will be used. Simply put, when querying the API using jsonp, the key was to first generate the next JSONP callback I ...

Is there a marble experiment that will alter its results when a function is executed?

Within Angular 8, there exists a service that contains a readonly Observable property. This property is created from a BehaviorSubject<string> which holds a string describing the current state of the service. Additionally, the service includes method ...

Guide on setting up redux store from server component using next.js and app router

I'm currently working with Next.js 13, React, and Redux to handle state management. My main objective is to fetch initial data on the server side and present it on the client side. Although I assumed this would be a typical approach with Redux and Ne ...

I seem to be stuck in an endless cycle with React hooks and I can't figure out the root cause

Explore the example here: https://codesandbox.io/s/wandering-wildflower-764w4 Essentially, my goal is to achieve the following: In the provided example, I have a server validation function that has been mocked. My objective is to maintain the state local ...

Using Typescript, Angular, and Rxjs to retrieve multiple HttpClients

I am looking to send get requests to multiple endpoints simultaneously, but I want to collect all the responses at once. Currently, this is how a single endpoint request is handled: public getTasks(): Observable<any> { this.logger.info('Ta ...

employing flush for lodash's throttle wrapper

When using TypeScript with JavaScript and Angular: I am trying to use the throttle decorator from lodash to limit an API call while a user is navigating around the page, ensuring that it fires before they leave the site. In my TypeScript constructor, I h ...

Exploring the power of Prosemirror with NextJS through Tiptap v2

Greetings everyone, I am a newcomer to Stack Overflow and I am reaching out for assistance regarding an issue that has arisen. The problem at hand pertains to the development of the Minimum Viable Product (MVP) for my startup which specializes in creating ...