最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to perform polling using angular signals and resource API - Stack Overflow

programmeradmin4浏览0评论

I have this scenario, where the database is updated regularly, for example say stock market prices (I do not need immediate updates a poll every 2 minutes is good enough).

Using short intervals like 2 or 5 seconds will lead to performance issues so I am choosing 2 minutes as my threshold for polling.

I want to implement a polling mechanism to update the values at the set interval.

Short and long polling

I know it can be done with push based systems, but I want to achieve this with pull/poll based system.

Below it the minimal reproducible code and working stackblitz for reference:

@Component({
  selector: 'app-root',
  imports: [CommonModule],
  template: `
    <div>{{rxResource.value() | json}}</div>
    <hr/>
    <div>{{resource.value() | json}}</div>
  `,
})
export class App {
  http = inject(HttpClient);
  serviceIdSignal: WritableSignal<number> = signal(1);
  rxResource = rxResource({
    request: () => this.serviceIdSignal(),
    loader: ({ request: id }) => {
      return this.http.get(`/${id}`);
    },
  });

  resource = resource({
    request: () => this.serviceIdSignal(),
    loader: ({ request: id }) => {
      return fetch(`/${id}`).then(
        (res: any) => res.json()
      );
    },
  });
}

The above code does not react/poll, my input signal stays the same, but I need to poll using resource API.

Stackblitz Demo

I have this scenario, where the database is updated regularly, for example say stock market prices (I do not need immediate updates a poll every 2 minutes is good enough).

Using short intervals like 2 or 5 seconds will lead to performance issues so I am choosing 2 minutes as my threshold for polling.

I want to implement a polling mechanism to update the values at the set interval.

Short and long polling

I know it can be done with push based systems, but I want to achieve this with pull/poll based system.

Below it the minimal reproducible code and working stackblitz for reference:

@Component({
  selector: 'app-root',
  imports: [CommonModule],
  template: `
    <div>{{rxResource.value() | json}}</div>
    <hr/>
    <div>{{resource.value() | json}}</div>
  `,
})
export class App {
  http = inject(HttpClient);
  serviceIdSignal: WritableSignal<number> = signal(1);
  rxResource = rxResource({
    request: () => this.serviceIdSignal(),
    loader: ({ request: id }) => {
      return this.http.get(`https://jsonplaceholder.typicode/todos/${id}`);
    },
  });

  resource = resource({
    request: () => this.serviceIdSignal(),
    loader: ({ request: id }) => {
      return fetch(`https://jsonplaceholder.typicode/todos/${id}`).then(
        (res: any) => res.json()
      );
    },
  });
}

The above code does not react/poll, my input signal stays the same, but I need to poll using resource API.

Stackblitz Demo

Share Improve this question edited 2 days ago D M 7,1794 gold badges18 silver badges37 bronze badges asked 2 days ago Naren MuraliNaren Murali 57.4k5 gold badges41 silver badges71 bronze badges 4
  • Polling is absolutely the wrong pattern to use in this scenario. Use websockets/grpc to keep the client/server in close synchronicity. – Rory McCrossan Commented 2 days ago
  • @RoryMcCrossan I have mentioned that I do not need it, I want pull based system, that too long polling – Naren Murali Commented 2 days ago
  • Then I'd suggest changing that requirement as polling will cause your system to have performance issues given a relatively low load. – Rory McCrossan Commented 2 days ago
  • @RoryMcCrossan If the polling is for a long interval, there will not be any performance issues. – Naren Murali Commented 2 days ago
Add a comment  | 

1 Answer 1

Reset to default 1

You can use the rxjs operator interval to trigger for a fixed number of seconds, this will create the polling trigger.

The interval is an observable, we need to convert it to a signal so that it can be used as an input for resource APIs, for this we use toSignal to convert it.

// we use rxjs interval to achieve polling of apis, enter the time in milliseconds
// long polling -> longer time
// short polling -> shorter time
// every 2 minutes
pollSignal = toSignal(interval(120000));

Then we pass this as an input to our resource APIs and polling should happen as expected.

rxResource = rxResource({
  request: () => ({ id: this.serviceIdSignal(), poll: this.pollSignal() }),
  loader: ({ request: { id } }) => {
    return this.http.get(`https://jsonplaceholder.typicode/todos/${id}`);
  },
});

resource = resource({
  request: () => ({ id: this.serviceIdSignal(), poll: this.pollSignal() }),
  loader: ({ request: { id } }) => {
    return fetch(`https://jsonplaceholder.typicode/todos/${id}`).then(
      (res: any) => res.json()
    );
  },
});

We can add a small loader using ResourceStatus to indicate a refresh.

<div>
  @if(![rs.Loading, rs.Reloading].includes(rxResource.status())) {
    {{rxResource.value() | json}}
  } @else{
    Loading...
  }
  </div>
    <hr/>
    <div>
  @if(![rs.Loading, rs.Reloading].includes(resource.status())) {
    {{resource.value() | json}}
  } @else{
    Loading...
  }
</div>

Full Code:

import {
  Component,
  WritableSignal,
  signal,
  resource,
  inject,
  ResourceStatus,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { HttpClient, provideHttpClient } from '@angular/common/http';
import { CommonModule } from '@angular/common';
import { rxResource, toSignal } from '@angular/core/rxjs-interop';
import { interval } from 'rxjs';
@Component({
  selector: 'app-root',
  imports: [CommonModule],
  template: `
    <div>
      @if(![rs.Loading, rs.Reloading].includes(rxResource.status())) {
        {{rxResource.value() | json}}
      } @else{
        Loading...
      }
      </div>
        <hr/>
        <div>
      @if(![rs.Loading, rs.Reloading].includes(resource.status())) {
        {{resource.value() | json}}
      } @else{
        Loading...
      }
    </div>
  `,
})
export class App {
  rs = ResourceStatus;
  http = inject(HttpClient);
  serviceIdSignal: WritableSignal<number> = signal(1);
  // we use rxjs interval to achieve polling of apis, enter the time in milliseconds
  // long polling -> longer time
  // short polling -> shorter time
  // every 2 minutes
  pollSignal = toSignal(interval(120000));
  rxResource = rxResource({
    request: () => ({ id: this.serviceIdSignal(), poll: this.pollSignal() }),
    loader: ({ request: { id } }) => {
      return this.http.get(`https://jsonplaceholder.typicode/todos/${id}`);
    },
  });

  resource = resource({
    request: () => ({ id: this.serviceIdSignal(), poll: this.pollSignal() }),
    loader: ({ request: { id } }) => {
      return fetch(`https://jsonplaceholder.typicode/todos/${id}`).then(
        (res: any) => res.json()
      );
    },
  });
}

bootstrapApplication(App, {
  providers: [provideHttpClient()],
});

Stackblitz Demo

发布评论

评论列表(0)

  1. 暂无评论