Parallel Execution Issue with RxJS Observable forkJoin

Struggling to understand why my requests aren't executing concurrently with the following code. As a newcomer to RxJS and observables, I would greatly appreciate any guidance on improving this snippet below. Essentially, I am fetching data from a REST API backend. Subsequently, for every element in the array of data, I'm calling a different endpoint using the 'forkJoin' operator. Despite sending all requests at once, they appear to execute sequentially rather than concurrently.

this.sites$.subscribe(data => {

    var obs: Observable<any>[] = [];
    for (var _i = 0; _i < data.length; _i++) {
        this.siteCaptureMap[data[_i].id] = new CaptureData();
        this.siteCaptureMap[data[_i].id].id = _i;
        obs.push(this.sitesService.getCaptureData(data[_i].nameOrNumber, data[_i].owner.name));
    }

    forkJoin(obs).subscribe(results => {
        for (var _i = 0; _i < results.length; _i++) {
            this.siteCaptureMap[data[_i].id].count = results[_i].length;
        }
    });

    this.dataSource.data = data;
    this.dataSource.filteredData = data;
});

Your assistance is highly valued. If further clarification or additional code snippets are needed, please do not hesitate to reach out. Thank you for your help!

Answer №1

When dealing with nested subscribe calls, it's important to be cautious of potential memory leaks and difficulty in unsubscribing. In such cases, consider using switchMap, concatMap, and mergeMap.

Although they have slight differences, all three operators switch to a new observable from the previous one. This article provides a detailed explanation of their distinctions.

For your situation, you could try implementing:

import { switchMap } from 'rxjs/operators';

...
this.sites$.pipe(
  switchMap(data => {
    let obs: Observable<any>[] = [];
    for (let _i = 0; _i < data.length; _i++) {
        this.siteCaptureMap[data[_i].id] = new CaptureData();
        this.siteCaptureMap[data[_i].id].id = _i;
        obs.push(this.sitesService.getCaptureData(data[_i].nameOrNumber, data[_i].owner.name));
    }

    return forkJoin(obs);
  }),
).subscribe(results => {
        for (let_i = 0; _i < results.length; _i++) {
            this.siteCaptureMap[data[_i].id].count = results[_i].length;
        }

        this.dataSource.data = data;
        this.dataSource.filteredData = data;
    });

Remember to use let and const instead of var. Also, if you notice all requests going out simultaneously, that indicates optimal performance. However, if they are processed sequentially, it could be due to either browser or server limitations.

Answer №2

To enhance the code's readability and conformity with rxjs standards, my approach would involve restructuring it to reflect a more idiomatic style. This would entail eliminating nested subscriptions, utilizing the pipe function, and embracing a functional programming approach. As indicated in inline comments, these modifications aim to clarify the code.

this.sites$.pipe(
  // Utilizing the rxjs map operator to transform data fetched from the rest api
  map(data => {
    // Generating an array of observables using JavaScript array's map method (note: not the rxjs map operator)
    obs = data.map((element, _i) => {
       this.siteCaptureMap[element.id] = new CaptureData();
       this.siteCaptureMap[element.id].id = _i;
       return this.sitesService.getCaptureData(element.nameOrNumber, element.owner.name)
    });
    // Returning both the array of observables and the original data
    return [data, obs];
  }),
  // Using concatMap to ensure sequential execution of async operations via forkJoin
  concatMap(([data, obs]) => forkJoin(obs).pipe(
    // Leveraging the rxjs map operator to include both results from forkJoin and initial data
    map(results => ([data, results]))
  ))
).subscribe(([data, results]) => {
  // Employing forEach loop to iterate through results and implement necessary logic
  results.forEach((res, _i) => this.siteCaptureMap[data[_i].id].count = res.length)
})

This revised structure aligns better with rxjs principles, emphasizing its functional essence while maintaining equivalence with the original script.

If you have mentioned that your code executes the calls within forkJoin sequentially, I would appreciate further insight into this claim.

Additionally, for an exploration of common rxjs usage patterns in conjunction with HTTP requests, feel free to peruse this informative article.

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

Issue with the useState hook not correctly updating a value

I'm a beginner in the world of react and I'm puzzled by why the title inside the h1 tag updates, but the url within the Image Component remains unchanged? Component Overview import React, { useState, useEffect, useContext } from 'react' ...

Find unique numbers within a specified range using NodeJS

I need to update my arts on an NFT test via OpenSea API, but I'm facing an issue where the numbers are being repeated. Is there a way to select a number within a range that does not repeat? Here is my current code: const opensea = require("opense ...

The Art of Checkbox Design

Seeking help in replacing the default check mark on a checkbox with an image. Here is the code snippet I am currently using: <html> <head> <style> .bl { background:-webkit-gradient(linear, left top, left bottom, color-stop(0, #175899), c ...

Error: The operation 'join' cannot be performed on an undefined value within Fast2sms

I am encountering issues while attempting to send SMS using fast2sms in Node.js. The error message reads as follows: TypeError: Cannot read property 'join' of undefined at Object.sendMessage (C:\Users\user\Desktop\node_module ...

The Outer Div Can't Contain Google Maps

I am currently working on integrating a map widget into a dashboard I created using gridstack.js. The sample widget layout that I am aiming for can be seen in the link below: https://i.sstatic.net/ZQP6G.png My goal is to embed the map within the inner (w ...

The error message "Unexpected token < in JSON at position 0" is indicating a SyntaxError in the

I am facing an issue with the API on this specific page. Although the API is working fine on other pages, it seems to be encountering a problem here. I'm not sure what's causing the issue. Below is the code snippet: export async function getStati ...

Issue with Dynamic Image Path in Require Function: Unable to locate the relative module

I've been struggling with an error in VueJs require function for the past two days. I'm attempting to pass a prop to the Home component and then display the image. Home.vue <template> <BlogPost :post="welcomeScreen"/> <B ...

Generate a high-resolution image using PhaserJS

I've been experimenting with creating graphics using PhaserJS and now I'm looking for a way to export them as high-resolution images or, even better, as vector-based graphics. Here's an example of the code I've been working on: var con ...

select specific region within image

I'm currently working on cropping an image and sending the cropped data to the server side. To achieve this, I am utilizing the imgareaselect plugin. While I am able to obtain the coordinates of the selection, I am facing challenges in actually croppi ...

Guide to hosting AngularJS Material documentation on a local server

After gathering the latest angularjs material, I noticed that the links in the document lead to absolute URLs at material.angularjs.org/.... I wish to have access to read the documentation and demonstration content locally. ...

Angular directive problem

Within the module, I have defined a directive but the <div> is not being highlighted as expected. test.directive.ts import { Directive, ElementRef, HostListener, Input } from "@angular/core"; @Directive({ selector: '[test]' }) expor ...

How to process JSON data that includes a function

I'm trying to replicate a similar diagram using dynamic input data. Here is a basic example of how I'm attempting to achieve this: <script> var myYears = ', 1991, 1992, 1993, 1994, 1995, 1998'; //auto-generated var myValues = ...

Guide to hosting a Razor partial view within Angular, without using IIS

Exploring an age-old topic on How to utilize ASP.Net MVC View .csthml as Angular View rather than .html I am seeking a similar solution but with Angular 15 and VS Code. My goal is to develop Angular components within VS Code for an ASP.NET MVC site (not W ...

Configuring vue-jest: Does anyone know how to set up aliases for template/script src attributes in Vue?

Dependencies: "@vue/cli-plugin-unit-jest": "^4.5.13", "@vue/test-utils": "^1.2.1", "vue-jest": "^3.0.7" I am dealing with an application that utilizes an alias (referred to as "foo") de ...

Tips for implementing self-managed state in Vue.js data object

My approach in organizing my Vue application involves using classes to encapsulate data, manage their own state (edited, deleted, etc), and synchronize with the back-end system. However, this method seems to conflict with Vue in some respects. To illustra ...

We were unable to locate a declaration file for the module known as 'firebase-tools'

As I delve into writing my inaugural cloud function for Firebase, I find myself in need of the firebase-tools module. To bring it on board, I updated my dependencies by editing the package.json file and executing the command npm install. Next, I attempted ...

Transferring information between an ASP web form page and an Angular2 application

Currently, I am working on a project that involves dealing with a legacy WebForms system. The system is gradually being updated to Angular 2, but the transition is happening incrementally. In order to effectively integrate information from the legacy sect ...

Dynamically loading JQuery causes highcharts to encounter errors

I have limited experience with JavaScript programming, and I've been encountering a persistent issue for quite some time now. Any assistance on this matter would be greatly appreciated. In the provided jsfiddle example, when jQuery is selected from t ...

[Simple TypeScript]: Assign the parameter value as the key of the object returned by the function

How do I modify the key of a function returned object to match its parameter's value? Here is my current code: const createCache = <A, T extends string>(name: T, base = {}) => { const cache = base; return { [name]: cache, } as { ...

Get the socket identification from ngx-socket-io

After incorporating ngx-socket-io into my project, I encountered a hurdle while attempting to obtain the socket id. Is there anyone who has knowledge on how this can be accomplished? (I am utilizing service initialization instead of the one in the app Mo ...