我有一个基于参数执行 http 请求的函数。我想添加某种“去抖动”功能。因此,如果函数在设定的时间窗口内被多次调用,我想将参数组合到一个请求中,而不是发出多个请求。
我想通过 Observables 和 Angular 实现这一点。这听起来并不复杂,但是我无法让它运行,也许我遗漏了什么。
现在让我们跳过单个请求中的组合,因为这可以通过聚合去抖动或 Oberservable.buffer 来完成。我在组合单个 Observable 时遇到了麻烦。
这是我到目前为止尝试过的方法。
我尝试使用主题,因为这似乎是这种情况下的合适对象 (https://stackblitz.com/edit/angular-hcn41v?file=src%2Fapp%2Fapp.component.ts)。
constructor(private http: HttpClient) {
this.makeRequest('1').subscribe(x => console.log(x))
this.makeRequest('2').subscribe(console.log)
setTimeout(() => {
this.makeRequest('3').subscribe(console.log)
}, 1000)
}
private makeRequest(id: string) {
this.observable = this.observable.pipe(
merge(Observable.of(id).pipe(delay(1)))
)
return this.aggregateDebounce(this.observable)
}
private getUrl(value) {
console.log('getUrl Call', value);
return 'https://jsonplaceholder.typicode.com/posts/1';
}
private aggregateDebounce(ob$) {
const shared$ = ob$.publishReplay(1).refCount()
return shared$.buffer(shared$.debounceTime(75))
}
我希望每个函数调用都有一个“getUrl 调用”日志和一个结果日志。但是,如果我对 this.makeRequest() 添加超过 1 个调用,我只会得到结果,结果也很奇怪。所有以前的值也总是返回。我想我不完全理解 Subject 在这种情况下是如何工作的。
另一种方法(取自此处RXJS: Aggregated debounce)是创建某种聚合去抖(https://stackblitz.com/edit/angular-mx232d?file=src/app/app.component.ts)
constructor(private http: HttpClient) {
this.makeRequest('1').subscribe(x => console.log(x))
this.makeRequest('2').subscribe(console.log)
setTimeout(() => {
this.makeRequest('3').subscribe(console.log)
}, 1000)
}
private makeRequest(id: string) {
this.observable = this.observable.pipe(
merge(Observable.of(id).pipe(delay(1)))
)
return this.aggregateDebounce(this.observable)
}
private getUrl(value) {
console.log('getUrl Call', value);
return 'https://jsonplaceholder.typicode.com/posts/1';
}
private aggregateDebounce(ob$) {
const shared$ = ob$.publishReplay(1).refCount()
return shared$.buffer(shared$.debounceTime(75))
}
在这种情况下,我遇到了问题,我也得到了所有以前的值。
理论上(至少对我而言)这两种变体听起来都是合理的,但我似乎遗漏了什么。任何正确方向的眨眼都会受到高度赞赏。
编辑:
根据要求,我添加了最终的现实世界目标。
想象一下从 API 请求信息的服务。在 50-75 毫秒内,您使用特定 ID 调用该服务。我想将这些 ID 组合到一个请求中,而不是执行 3 个请求。如果 100 毫秒后再次调用该服务,将完成一个新请求
最佳答案
this.makeRequest(1).subscribe();
private makeRequest(number: number) {
this.values.next(number);
return this.idObservable.pipe(
您在订阅之前发出值 -> 值丢失。
private values: Subject = new Subject();
private idObservable = this.values.pipe(
private makeRequest(number: number) {
this.values.next(number);
return this.idObservable.pipe(
每次调用都会根据主题创建一个新的可观察对象。每当您发出一个值时,所有订阅者都会收到该值。
一个可能的解决方案看起来像这样(我在这里使用新的 rxjs 语法):
subject: Subject<String> = null;
observable = null;
window = 100;
constructor() {
this.subject = null;
this.window = 100;
this.makeRequest('1').subscribe(console.log)
this.makeRequest('2').subscribe(console.log)
setTimeout(() => {
this.makeRequest('3').subscribe(console.log)
}, 1000)
}
private makeRequest(id: string) {
if (!this.subject) {
this.subject = new ReplaySubject()
this.observable = this.subject.pipe(
takeUntil(timer(this.window).pipe(take(1))),
reduce((url, id, index) => this.combine(url, id), baseUrl),
flatMap(url => this.request(url)),
tap(() => this.subject = null),
share()
)
}
this.subject.next(id);
return this.observable;
}
combine
创建 url,request
发出实际请求。
关于javascript - Observable 将多个函数调用组合成单个 Observable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50722324/