TLDR; I would like to use debounceTime to execute the function only if 300 milliseconds have passed without it being called. In the meanwhile, I also want to be able to trigger the function every 1 minutes If the process takes a long time. Otherwise, the function will only be triggered at the end of the process.
Basically, our system has a long process that will fire a lot of SignalR update to the client. When I received the server command on the client, I will make 2 additional HTTP requests back to server to get some information. So that It will hit the server back as long as the server sending me update.
I am using
debounceTime
to prevent sending too many requests back to the server If the time between two commands is within 300ms. But there is one use case where the server constantly sending the update to the client in, e.g 1 hour. Meaning the client will trigger the getItemCount at 1h and 300ms.
export class LeftNavigationComponent implements OnInit, OnDestroy {
typeACount: number = 0;
typeBCount: number = 0;
constructor(
private itemService: service.ItemService,
private signalR: service.SignalRService) { }
ngOnInit(): void {
this.subscriptions = [
this.signalR.itemCreated.debounceTime(300).subscribe(item => this.onUpdatingData())]
}
onUpdatingData() {
Promise.all([
this.itemService.getItemCount(APP_SETTING.TYPE_A),
this.itemService.getItemCount(APP_SETTING.TYPE_B)])
.then(response => this.gettingCountDone(response))
}
gettingCountDone(response) {
this.typeACount = <any>response[0];
this.typeBCount = <any>response[1];
}
}
I still want to debounceTime
to prevent sending too many requests to the server. But it should be smart enough to be automatically triggered every e.g 1 minutes after receiving the first updated. Has anyone had the use case before?
Here's my take on it. The code is way way less elegant than one written by Pavel.
You can try it out in the plunker I prepared. (You'll need to open browser console to see the generated output stream). You may also want to play with the
normalEventDebounceTime
andforcedInterval
key configuration parameters, and/or with the event timing insourceObservable
.The idea is to
merge
two streams (sourceObervable
andreschedulingObservable
) into one which will be triggered by either of the inputs. Whenever the merged observable emits an event, we callreschedulingSubject.next()
thus delayingreschedulingObservable
by1000ms
(because it's constructed withdebounceTime
applied toSubject
).The
sourceObservable
is supposed to be truly independent, i.e. produced by user input, or -- in your case -- by SignalR as I understand.That code produces the following stream:
Pros of this code are:
setTimeout(() => reschedulingSubject.next('forced-next'), 100)
).Cons are:
Subject
which is a last resort kind of a thing, IMO.Again, you asked a very good question. Always interesting to deal with puzzles like this. Starring the question!
Pavel answer is close, but If I have understood well the question, you want this:
This code will do the following, when the time between items created are major than 300ms onUpdatingData() will be called. After that Every time debounced emits a value, a throttleTime observable of 1 minit is created. Meaning that, if debounced doesn't emit for a minut since the last emision, onUpdatingData() will be executed, and so one.
And improvement would be to merge the observables, because they are from the same type and the execute the same function, for example like this:
I posted a fiddle showing the working solution. In this fiddle, the event mousedown simulates the stream this.signalR.itemCreated.
https://jsfiddle.net/llpujol/e6b6o655/
This is my take on it - if I understood the question correctly, which I'm not sure of... Nevertheless, code is below.
This produces the following sequence:
PS. And I agree with Igor - that's an interesting brainteaser, thanks for interesting question!
You can use
throttleTime
(60000)
instead of or in parallel withdebounceTime
. To check this behavior move all balls to the beginning and you will see the resultIn your case you can for example do the following:
So method won't be called too often and also once per minute (or less if there is no events).
It is also possible to write your own implementation and combine
debounceTime
withthrottleTime
but I'm not experienced enough too provide such example...