【问题标题】:Observable Continue calling API and changing parameters based on conditionObservable 继续调用 API 并根据条件更改参数
【发布时间】:2017-02-09 09:31:08
【问题描述】:

我已阅读 Rx.js repeat 文档,以了解如何根据从 API 收到的响应继续调用 api。我打电话给API,它一次只能发回2k 记录。 API 将返回一个值让我发送,以便我可以继续接收记录,直到它们返回完成值。

所以流程如下:

  1. 发出GET请求查询参数reqMode=''
  2. 使用包含reqModevaluedone 的最后一个数组检索响应。
  3. 如果我收到value,那么我需要发出相同的请求,但发送带有值的reqMode 参数。
  4. 如果我收到done,那么我将停止并返回自第一次通话以来的所有记录。

subscribing normally 时我得到了第一组值,但这是我阅读文档后的尝试,但这没有意义:

getRecords(){
    let url = this.url + 'reqMode=';
    return this.http.get(url)
            .doWhile() //What would I do here
}

当尝试使用 Observable<response> 类型的 Observable 执行 .doWhile 时。我正在寻找使用 Observables 来完成我需要做的任何替代方案。

【问题讨论】:

  • angular2 附带 rxjs5-beta 并且基于文档,您将无法使用 .doWhile... 至少目前还不能:github.com/ReactiveX/rxjs/blob/master/…。您在寻找替代解决方案吗?还是只适用于 rxjs4?
  • 我可以选择替代方案。

标签: angular typescript rxjs rxjs5


【解决方案1】:

我不认为repeat() 是一个很好的运营商。如果我理解正确,您想根据上一个请求的响应重复 HTTP 请求。如果您想多次重复相同的请求,操作符repeat() 非常适合。

我会使用concatMap() 并递归调用自身,直到reqMode 等于"done"

观看现场演示:http://plnkr.co/edit/w0DdepslTaKrLSB3aIkA

import {Observable, Subject} from 'rxjs';

const result = new Subject();
const closeBuffer = new Subject();
const buffer = result.buffer(closeBuffer.asObservable());

function sendHttpRequest(reqMode) {
  return Observable.of('{"reqMode":' + reqMode + '}')
    .map(response => JSON.parse(response))
    .concatMap(data => {
      console.log('HTTP Response:', data);
      // Add data to the buffer of results
      result.next(data);

      if (data.reqMode == 'done') {
        // Return an empty value wrapped as an Observable so concatMap can work
        // with it and emit onNext when it completes (which is immediately
        // thanks to the `.of()` operator).
        return Observable.of(null);
      } else {
        // Simulate that the next call returns 'done'
        return sendHttpRequest('"done"');

        // Uncomment this for real usage
        //return sendHttpRequest(data.reqMode);
      }
    });
}

// Subscribe to the buffer where I'll receive the value.
buffer.subscribe(val => console.log('Next: ', val));

// Simulate HTTP request with reqMode = 42
sendHttpRequest(42).subscribe(() => {
  console.log('done');
  // Emit values from the buffer.
  closeBuffer.next(null);
  closeBuffer.complete();
});

我使用of() 运算符来模拟请求并返回包装为 Observable 的值。我还使用Subject 来保存使用buffer() 运算符缓冲的所有响应。我订阅缓冲区以获得最终的响应数组(如果您将此代码包装到一个函数中,您很可能会返回buffer,您可以稍后再订阅)。

响应如下:

HTTP Response: Object {reqMode: 42}
HTTP Response: Object {reqMode: "done"}
Next:  [Object, Object]

查看类似问题:Angular 2 + rxjs - how return stream of objects fetched with several subsequent http requests

【讨论】:

  • 看起来不错! recursion 一直是我的弱点。是时候进入一个新的领域了……我现在就试试这个
  • @inspired 我更新了我的答案,直到done 我才意识到你想要堆叠所有回复,这意味着我猜可能有多个(?)现在它有点复杂但我认为还是可以理解的。
  • 哦,我正在尝试您的方法,只是将每个数据响应推送到一个数组以便将它们全部收集起来,但我想这会将我的方法耦合到一个外部数组。
  • @inspired 是的,这也是一个选项。我认为您需要有一个单独的变量来放置结果,因为 Observable 链适用于 HTTP 响应。更多“功能方式”会调用sendHttpRequest()以及累积的结果数组(如sendHttpRequest('"done"', [obj1, obj2])),但这会让人很困惑,甚至没有必要。
  • 我还没有尝试过缓冲区,但是将值连接到数组效果很好!
【解决方案2】:

所以我举了一个例子,说明如何通过使用包装 observer 和使用 .repeat() 来做到这一点。

所有的逻辑都在app.component.ts

Checkout this plunker

我在代码中留下了 cmets,但本质上它会发出一个 http 请求,它会增加一个计数,然后会发出另一个带有不同查询号的请求。它将重复直到达到 5。

您必须对其进行修改,以便“重复条件”代表您的逻辑。

希望有帮助!

【讨论】:

  • @mrcolombo - 你将如何添加一个间隔以便每秒重复一次动作?
  • @DonalRafferty 在.repeat() 之前添加.delay(1000) 将使其每秒执行一次。
猜你喜欢
  • 1970-01-01
  • 2020-04-21
  • 1970-01-01
  • 2020-01-19
  • 2020-01-30
  • 1970-01-01
  • 2022-01-23
  • 2016-05-31
  • 1970-01-01
相关资源
最近更新 更多