Leveraging Angular's Observables to Defer Multiple API Requests within a Specified Timeframe

In my Angular 4 app, I have a setup like this (for illustration purposes, I've omitted some code)

@Injectable()
  export class SomeService {

    constructor(
      private http: Http
    ) {
    }

    get(id: number) {
      return this.http.get('http://somedomain/somemodel/${id}.json');
    }

  }
  

This service is utilized by various components to make API calls.

constructor(private someService: SomeService) {}
  ...
  someMethod() {
    // code here...
    this.someService.get(2).subscribe( someHandlerFunction );
  }

  someOtherMethod() {
    // more code here...
    this.someService.get(2).subscribe( someHandlerFunction );
  }
  

The issue at hand is uncertainty around the timing of when someMethod() and someOtherMethod() will be triggered. Sometimes both may be initiated, resulting in two API calls. My aim is to find a way to modify the Service so that the request is only made after a specified timeframe. I attempted to use debounce:

get(id: number) {
    return this.http.get(`http://somedomain/somemodel/${id}.json`).debounceTime(10000);
  }
  

I expected that with this approach, the HTTP get request would only occur once every 10 seconds. If a new request is sent within this interval, it would not trigger another call but rather emit the latest value from the observable. However, this method didn't provide the desired outcome. Any suggestions?

PS: While I understand that utilizing a flag could help manage this, it proves to be inefficient as my application has multiple services handling numerous HTTP requests.

Your thoughts on this?

Answer №1

It is recommended to apply debounce on the observable triggering the http service, rather than directly on the http request itself. This way, you can achieve a smoother flow of events.

myObservable
  .changes
  .debounceTime(800)
  .subscribe(// Make the http call here)

You can find a more detailed explanation on this topic in a related discussion here.

Answer №2

One way to optimize your application with RxJS is by implementing caching for your results. By setting up an interval that clears the cache periodically, you ensure that new requests can be made without overloading your server or database. This strategy is especially useful for preventing redundant queries every time a page is loaded, particularly when no new data has been added.

While this approach may require more code than other solutions, it offers several advantages:

  • Efficiently caching results helps reduce the load on your server and database.
  • Unlike simply using debounceTime, this method not only blocks requests but also provides cached results. By utilizing this technique, you can still access previous data if needed while delaying new requests until necessary.

Implementing result caching:

Class ProjectService {
    private cachedProjects: Observable<Project[]>;

    all(): Observable<Project[]> {
        if (!this.cachedProjects) {
            this.cachedProjects = this.httpService.get(`${this.url}/project`)
                .map(res => res.data.map(project => new Project(project)))
                .publishReplay()
                .refCount();
        }

        return this.cachedProjects;
    }
}

When calling the service:

this.projectService.all().subscribe((projects: Project[]) => {
    // The initial call will fetch 'projects', subsequent calls will use cached data
});

To control how frequently HTTP calls are blocked, you can introduce an interval mechanism in your service. Update your service as shown below:

Class ProjectService {
    private cachedProjects: Observable<Project[]>;

    constructor() {
        setInterval(() => {
            this.cachedProjects = null;
        }, 5000); // Set interval to clear cache every 5 seconds
    }

    all(): Observable<Project[]> {
        if (!this.cachedProjects) {
            this.cachedProjects = this.httpService.get(`${this.url}/project`)
                .map(res => res.data.map(project => new Project(project)))
                .publishReplay()
                .refCount();
        }

        return this.cachedProjects;
    }
}

With this setup, you can make fresh requests every 5 seconds while leveraging cached projects during intervals.

Answer №3

I encountered a similar problem, and my approach involved creating an rxjs subject to emit an id.

@Injectable()
export class SomeService {
  private idSubject = new Subject<string>();
  
  constructor(private http: Http) {
    this.idSubject.asObservable().distinctUntilChange()
        .subscribe((id) => {
              this.http.get('http://somedomain/somemodel/${id}.json')
            });
  }

  get(id: number) {
    this.idSubject.next(id);
  }
}

Although my solution may not be an exact match for your requirements, you have the flexibility to customize it according to your specific needs.

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

Encountering a 404 error when trying to retrieve the Next.js 14 API route, despite specifying the use of route

Currently, I am working with Next.js version 14.2.3 and attempting to access the /api/tmp API route from the chat.tsx component. However, I keep encountering a 404 error even though I am using the route.ts file. What could be causing this issue? UPDATE: C ...

Integrating external JavaScript libraries into Ionic using the correct process

For the last few months, I have been utilizing jQuery Mobile for a hybrid app. Now, I am interested in exploring Ionic and Angular.js, so I am attempting to reconstruct it. My current JQM application relies on xml2json.js, but I do not have any experience ...

Troubleshooting Multer to fix image payload issues in a Node.js and React.js application

Currently, I am facing an issue while trying to send an image from my ReactJS frontend to my NodeJS Express backend using formData. Despite seemingly correct data transmission, the image does not appear in the payload and triggers this error from the backe ...

Is there a way to extract information from an external XML document and incorporate it into an HTML file?

I am attempting to extract information from an XML file that is not stored on my website's server. My goal is to utilize this data for various purposes, such as generating charts. One specific example involves using weather data from an XML file locat ...

Passing a JavaScript object that may be undefined to a pug template in Node.js

My journey requires transferring a set of JavaScript objects to the pug template. router.get('/edit/:itemObjectId', async function(req, res, next) { var itemObjectId = req.params.itemObjectId; var equipmentCategoryArr = []; var lifeE ...

Adding an await tag to dispatch causes issues with performing a react state update on an unmounted component

I recently added an await tag to a redux dispatch and now I am encountering the following error message: index.js:1 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your applica ...

What is the best way to reset the state in React prior to the render being called?

Whenever I click on a copy icon, a popup is displayed. This happens because the state "showPopup" is set to true upon clicking the copy icon, and the render function recognizes this and shows the popup. The popup will close automatically if I click anywher ...

What is the most effective way to obtain a customer's latitude and location by prompting them to drop a pin on Google Maps?

My Android app has an API, but on my website I'm wondering how I can retrieve a person's location by having them place a marker on a Google Map. Is there a standard method for this? I need to obtain the latitude and longitude coordinates and send ...

Apache conf file configured with CSP not functioning properly when serving PHP files

While configuring the Apache CSP lockdown for a site, I encountered an unusual behavior when opening the same file as a PHP script compared to opening it as an HTML file. The HTML file looks like this: <html> <head> <meta http-equiv= ...

Switching between classes using jQuery

I'm working on implementing a play and pause button for a video, and I'm facing an issue with switching the class when the button is pressed. What I want is that when the pause button is clicked, the class changes to something else, and vice vers ...

Styling a Bootstrap 4 Popover with customized content

In my Angular 4 application, I am interested in creating a popover with HTML formatted content. After checking out the documentation and cheat sheets, I came across an example like this: <button type="button" class="btn btn-secondary" data-container="b ...

Why is the Axios instance/function not being passed the argument?

I am currently working on refactoring a next.js App that has a functioning axios call. However, I have encountered an issue with my new function not receiving arguments. The problem consists of two main components: my next.js page and an external custom m ...

What is the best way to determine which DOM element is clicked when using the OnClick event? Can

Upon clicking an element: I seek to pinpoint the exact element. To prevent selecting multiple elements (e.g. with the same class) (and with or without an id), I am considering retrieving the absolute location/path in the DOM. Strategy: I have devised two ...

Assign a variable to set the property of a class

Could something similar to this scenario be achievable? const dynamicPropName = "x"; class A { static propName = 1 // equivalent to static x = 1 } A[dynamicPropName] // will result in 1 or would it need to be accessed as (typeof A)[dynamicPropN ...

Manipulating the information pulled from an external PHP script that is currently being displayed

Although I don't consider myself a professional, I am determined to learn some web languages this summer to be able to turn my design ideas into prototypes. Currently, I am struggling to figure out how to manipulate elements that are being echoed bac ...

Understanding NestJS Mixins and Their Distinction from Inheritance

After researching, I found that the Nestjs documentation does not include any information about mixins. Here is what I have gathered from my findings on Google and Stack Overflow: A mixin serves as a means of code sharing between classes within Nest. Esse ...

Converting Plain JSON Objects into a Hierarchical Folder Structure using Logic

Looking at the data provided below: [ {name: 'SubFolder1', parent: 'Folder1'}, {name: 'SubFolder2', parent: 'SubFolder1'}, {name: 'SubFolder3', parent: 'SubFolder2'}, {name: 'Document ...

When attempting to implement a UtilityProcess in Electron with TypeScript, the error "SyntaxError: Cannot use import statement outside a module" is encountered

Seeking a way to initiate a background process in Electron's main process to handle heavy socket operations without interfering with the main process. Previously, this task was accomplished within a hidden window renderer. Recent recommendations sugg ...

Unexpected JSON token error occurs in jQuery when valid input is provided

I encountered an error that I'm struggling to pinpoint. The issue seems to be related to the presence of the ' symbol in the JSON data. After thoroughly checking, I am positive that the PHP function json_encode is not responsible for adding this ...

Supply additional parameters to the method decorator within an Angular component

Imagine a scenario where there are multiple methods requiring the addition of a confirmation dialog. In order to streamline this process, a custom decorator is created. @Component({...}) export class HeroComponent { constructor(private dialog: MatDialog ...