0

There are lot of discussions on this topic but still i am not able to figure out which one i need to use for my usecase. I have a method that needs to be called every 3 seconds to get updated stock details .

ngOnInit() {
  
  this.getUpdatedStock(); // to get data while loading page for first time
  this.interval = setInterval(()=> {
    this.getUpdatedStock();
   },3000)

}

whereas getUpdatedStock() calls the service and do some manipulations before rendering data .

getUpdatedStock(){
   this.stockService.getStockData().subscribe((data)=> {
   this.latestStock = data ;
   // few lines of code to highlight table headers based on response
})}

As expected the setInterval() , the request gets stacked up if there is delay in response and also the calls are not happening after 3 seconds since the last response is received . Then i found following thread which explains the use of rxjs methods

Why would I use RxJS interval() or timer() polling instead of window.setInterval()?

There also some suggestions been made not to go with rxjs for that usecase as it may increase bundle size . Now i am thinking of which one to use for my usecase . I dont want calls to happen until i receive response from previous request and it should 3 seconds since i received the response . Is it possible to do with setInterval() itself or i have to go with rxjs . If i have to go with rxjs timer() or interval() can someone please tell me how that can be done as i am not calling the service directly . I am calling method within which service call is triggered and data manipulations are done .

ani
  • 446
  • 1
  • 9
  • 31

1 Answers1

1

An RxJS solution:

RxJS does make this sort of thing really easy. Also, you mostly just get increased bundle size based on what you use. I'll leave the deliberation up to you and show you I would implement this with RxJS.

Here I merge a silent timer with your getStockData. The timer just ensures that the merged observable does not complete before 3 seconds. If getStockData takes more than 3 seconds, the timer is ignored.

Then I repeat this for forever.

ngOnInit() {
  
  merge(
    this.stockService.getStockData(),
    timer(3000).pipe(filter(_ => false))
  ).pipe(
    repeat(),
  ).subscribe({
    next: this.updateStock
  });

}

updateStock(data){
  this.latestStock = data;
  // few lines of code to highlight table headers based on response
}

Update # 1:

Explaining filter:

timer(3000) will emit the number 0 after 3 seconds. We actually don't want the timer to emit anything. It's just there as a lower-bound on the length of your observable. So, in order to stop it from emitting any values, we silence it by filtering everything.

filter(_ => false) says "no matter what the value is, do not allow it to pass".

timer(3000).pipe(filter(_ => false)) will emit nothing and then send complete event.

The effect here is that even if this.stockService.getStockData() takes 1 second to complete. The merge will still wait and 2 seconds (for a total of 3 seconds) before the merged streams complete. On the other hand, if this.stockService.getStockData() takes more than 3 seconds to complete, then the merged streams will complete immediately after this.stockService.getStockData() completes.

Explaining repeat:

repeatWhen(a => a) is actually the same as just using repeat(). I used the first because I thought you had to give repeat a number, but you don't.

Repeat does exactly what it sounds like it does. When the source stream completes, it just re-starts it again. repeatWhen gives you some fine-grained control over that process, but you don't need it given what you've described.


Update # 2:

Are you talking about just repeating after a delay of 3 seconds?

Whenever stockService.getStockData() completes, this will wait 3 seconds and then call stockService.getStockData() again.

This means if the first call to stockService.getStockData() takes 5 seconds, then the second call happens at 8 (5 + 3) seconds.

ngOnInit() {

  this.stockService.getStockData().pipe(
    repeatWhen(co => co.pipe(
      delay(3000)
    )),
  ).subscribe({
    next: this.updateStock
  });

}

updateStock(data){
  this.latestStock = data;
  // few lines of code to highlight table headers based on response
}
Mrk Sef
  • 7,557
  • 1
  • 9
  • 21
  • Thank you so much for the response. Can you please explain me the code if you don't mind. – ani Sep 14 '21 at 12:55
  • :) I explained it a little in the answer already. If you have any questions, maybe I can help explain more. – Mrk Sef Sep 14 '21 at 12:59
  • I couldnt understand the usage of filter and repeatWhen here . so if you could explain what's really happening in this piece of code it will be helpful. I dont have much idea on rxjs . Sorry. Am trying to learn – ani Sep 14 '21 at 13:28
  • @ani Sorry for the slow response. I've tried to explain a bit more. – Mrk Sef Sep 16 '21 at 20:00
  • Thanks for the detailed answer . But I want to check on the second scenario if the methods takes more than 3 seconds . Actually the service call takes 5 seconds to complete . So here I want next service call to be triggered 3 seconds since I receive the response . – ani Sep 17 '21 at 05:11
  • @ani Can you explain better? I don't understand at all . How can a call that takes 5 seconds give a response in 3 seconds? – Mrk Sef Sep 17 '21 at 11:54
  • @ani I've made another update. Not sure if it helps as I'm very confused about what you want. – Mrk Sef Sep 17 '21 at 14:38
  • May be I will explain more .. my service call has to be triggered every 3 seconds . At times when the data is huge service call takes 5 seconds to complete . So before the previous call completes the next call is been triggered . Hence I want my subsequent calls to be triggered only if previous call is completed and 3 seconds since it is completed . – ani Sep 17 '21 at 16:09
  • @ani It sounds like you just want to repeat after a delay of 3 seconds. Which is what Update # 2 above does. Does that seem right? – Mrk Sef Sep 17 '21 at 16:45