javascript - Observable 将多个函数调用组合成单个 Observable

标签 javascript angular typescript rxjs observable

我有一个基于参数执行 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/

相关文章:

node.js - Visual Studio代码: "' tslib' cannot be found"error in Angular project

angular - 在 angular 6 项目中实现多个 mat-icon 相同的 svg 图标出现在多个地方

angular - 为什么 ngx-mat-select-search 在此示例中不能处理动态数据?

javascript - typescript 并将对象转换为字符串

javascript - 在 jQuery 中选择先前单击项目的子项

javascript - 使用对象解构时省略属性变量

javascript - Object.将 this 与 NodeList 一起分配

javascript - 使用express router时html渲染不显示nunjucks变量

Angular 2后台任务

javascript - Angular2/TypeScript 和 HTTP : How to attach object to component?