【问题标题】:Cascading ajax calls with RxJs使用 RxJs 级联 ajax 调用
【发布时间】:2016-11-03 00:55:55
【问题描述】:

我如何级联 RxJs 调用以从这个人为的服务中检索数据。

第一个请求转到 /customer/1

/客户/:id

回应:

{
   Name: "Tom",
   Invoices: [1,3],
   Orders: [5,6]
}

在客户响应中,我们使用 2 个 InvoiceId 来访问第二个服务:

/invoices/:id

回应

{
  Id: 1,
  Amount: 10
}

在客户响应中,我们使用 2 个 OrderId 来访问第三项服务:

/orders/:id

回应

{
  Id:2,
  Date: '2016-11-12'        
}

最后我想设计一个像这样的对象:

{
   Name: "Tom",
   Invoices: [
    {
      Id: 1,
      Amount: 10
    },
    {
      Id: 3,
      Amount: 5
    }],
   Orders: [
   {
     Id:5,
     Date: '2016-11-12'        
   },
   {
     Id:6,
     Date: '2016-11-12'        
   }]
}

如何通过管道传递 id 以便检索依赖对象。

我的直觉告诉我我可能应该使用 flatMap 运算符,但我完全不确定这一切如何协同工作。

var ajax = Rx.DOM.getJSON('/api/customers/1')
    .flatMap(p => p.Invoices.map(x =>
        Rx.DOM.getJSON('/api/invoices/' + x)
        ));

【问题讨论】:

  • Rx 可能不是这里工作的正确工具。使用 Promises 和 fetch()

标签: javascript rxjs


【解决方案1】:

这是一个典型的用例,您需要从多个 HTTP 调用中构建响应:

const Observable = Rx.Observable;

var customerObs = Observable.create(observer => {
    Observable.of({Name: "Tom", Invoices: [1,3], Orders: [5,6]})
        .subscribe(response => {
            var result  = {
                Name: response.Name,
                Invoices: [],
                Orders: [],
            };

            let invoicesObs = Observable.from(response.Invoices)
                .flatMap(id => Observable.of({ Id: Math.round(Math.random() * 50), Amount: Math.round(Math.random() * 500) }).delay(500))
                .toArray();

            let ordersObs = Observable.from(response.Orders)
                .flatMap(id => Observable.of({ Id: Math.round(Math.random() * 50), Amount: Math.round(Math.random() * 500) }).delay(400))
                .toArray();

            Observable.forkJoin(invoicesObs, ordersObs).subscribe(responses => {
                result.Invoices = responses[0];
                result.Orders = responses[1];

                observer.next(result);
            });

        });
});

customerObs.subscribe(customer => console.log(customer));

观看现场演示:https://jsfiddle.net/martinsikora/uc1246cx/

我使用Observable.of() 来模拟 HTTP 请求,flatMap() 将每个发票/订单 ID 转换为重新发送的 Observable(另一个 HTTP 请求),然后使用 toArray() 收集从运营商链发出的所有值并将它们重新发送到一个数组中(只是因为它很方便)。

操作员forkJoin() 等待所有源 Observable 完成,然后将它们的最后一个值作为数组发出(因此我们在 responses 中使用数组数组)。

查看类似问题:Performing advanced http requests in rxjs

【讨论】:

  • 这已经非常接近了。我用正确的 Rx.DOM.getJSON('/api/orders/' + id) 调用替换了 Observable.Of 调用。 customerObs.subscribe 的解析速度比 getJSON 的网络调用快。这样,执行 console.log 时 Orders 和 Invoces 仍然是空的。我需要以某种方式加入他们吗?
  • @Marius 啊,你是对的!理想情况下使用forkJoin(),请参阅我的更新答案。
  • @martin 如果您使用 API 调用,您将如何更改该代码?那么Observable.create()还有必要吗?
猜你喜欢
  • 2020-07-22
  • 2022-07-28
  • 2019-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-30
  • 2021-04-05
  • 2017-08-23
相关资源
最近更新 更多