Reputation: 208
I am trying to implement a buffer inside an angular service to prevent an http call to go out multiple times should it get called multiple times in rapid succession. To achieve this, I'm using the debounceTime operator and a BehaviourSubject to instantly emit its last value on every new subscription.
@Injectable({
providedIn: 'root'
})
class MyService {
private requestBuffer = new BehaviorSubject<any>(null);
private requestBuffer$ = this.requestBuffer
.asObservable()
.pipe(
debounceTime(1000),
mergeMap(() => this.http.get('/myurl'))
);
constructor(private http: HttpClient) { }
doRequest() {
return this.requestBuffer$;
}
}
@Component({
selector: 'app-my-component-1'
})
class MyComponent1 implements OnInit {
constructor(private myService: MyService) { }
ngOnInit() {
this.myService.doRequest()
.subscribe()
}
}
@Component({
selector: 'app-my-component-2'
})
class MyComponent2 implements OnInit {
constructor(private myService: MyService) { }
ngOnInit() {
this.myService.doRequest()
.subscribe()
}
}
@NgModule({
imports: [
CommonModule
],
declarations: [
MyComponent1,
MyComponent2
],
providers: [
MyService,
]
})
class MyModule {
constructor() { }
}
<app-my-component-1 />
<app-my-component-2 />
The above code is not working and I'm not really understanding what am I doing wrong. As both components reach their OnInit lifecycle hook, I expected that HttpClient's get method would be debounced and only called once. However, this is not the case, two get calls are being fired.
I hope that the explanation is clear enough.
To my end goal of obtaining a buffered http call, what is it that I'm doing wrong / misunderstanding?
Thank you!
Upvotes: 2
Views: 2219
Reputation: 71961
You have to add the share()
operator to share the observable between multiple subscriptions:
private requestBuffer$ = this.requestBuffer
.asObservable()
.pipe(
debounceTime(1000),
mergeMap(() => this.http.get('/myurl')),
share()
);
You don't need to use a BehaviourSubject if you use shareReplay()
, but in the end, it doesn't really matter.
To 'ditch' the BehaviourSubject, I suspect this should be enough:
class MyService {
private requestBuffer$ = this.http.get('/myurl').pipe(
debounceTime(1000),
shareReplay()
);
constructor(private http: HttpClient) { }
doRequest() {
return this.requestBuffer$;
}
}
Although I'm afraid if you do two calls, and they are more than 2 seconds apart, the 2nd call does not fire, but you should test that out yourself
Upvotes: 4