javascript - 在 Angular 2+ 中按顺序订阅可变数量的 Observable

标签 javascript angular typescript rxjs observable

抱歉,如果这个问题在其他地方得到了回答,我尝试搜索,但我什至不确定我在寻找什么。

假设我有这个对象可以使用:

userRequest: {
    id: number,
    subject: string,
    ...
    orderIds: number[]
    ...
}

order: {
    id: number,
    ...
    clientId: number,
    productIds: number[]
}

client: {
    id: number,
    name: string,
    ...
}

product: {
    id: number,
    name: string,
    price: number
}

现在,在某个时刻,用户将使用该复合对象填写表单并将其发送以供分析。但在发送之前,必须首先对其进行验证。我无法在表单中进行验证,因为用户只是输入纸上收到的数据。如果数据“无效”,将发送提供更多信息的请求。

因此,我需要验证请求,还需要验证订单、产品和客户。我被要求显示“验证请求”屏幕,并在检查每个元素后显示“有效”或“无效”屏幕。足够简单。

但是现在,我正在发送 http 请求并让 Observables 进行处理。我正在尝试更多地了解它们以及所有可用的运算符以及如何混合它们,但目前我完全迷失了。

所以,我首先得到一个Observable<userRequest>来自服务器。然后,一旦我收到 userRequest,我需要从他们的 id 中获取所有订单,当我收到“订单”时,我必须获取客户及其产品。

所有这些都是异步完成的,但是在收到订单之前我无法获取客户或产品,并且我需要 userRequest 来提供订单。此外,当我收到订单时,我需要“同时”获得客户和产品,因为他们都需要相同的订单......?对于总决赛,对于我得到的每个元素(请求、订单、客户、产品),我需要验证它并等待每个元素说“请求有效”或无效。

所以继续:

  1. 我需要获取 Observable<userRequest>并验证
  2. 现在,我必须获得 Observable<order[]>并验证每个订单
  3. 对于每个订单,我必须 1) 获得 Observable<Client>并验证 PLUS 2) 获得 Observable<Product[]>并验证每一个
  4. 等待每个可观察量完成并检查其是否有效

步骤 1 和步骤 2 需要顺序执行,但是当步骤 2 完成时,我需要对步骤 2 的每个结果执行步骤 3.1 和 3.2。然后等待。

我确信这还很不清楚,我只是希望它足够清楚,这样你们就能明白我想要实现的目标。如果您对我有任何提示,请分享! ; )

编辑

我确实知道需要做什么。但我失去冷静的地方是,当我需要按顺序链接可观察对象时(因为每个可观察对象都依赖于前一个),在不同的点上我需要调用验证方法,并且当涉及到客户端和产品时,两者都需要其 ID 的订单。我确实尝试了很多很多方法,但我只是没有完全理解这个概念。

bygrace - 不,我不希望验证被阻止。它应该验证所有内容,因为这将导致请求所有丢失或无效的部分,并且应该在最后显示。这就是为什么我需要一种方法来知道一切何时完成,以便我可以检查是否发现错误。

请求、订单、客户和产品均来自各自的服务。该服务发出 http 请求并返回一个 Observable。因此,我需要链接调用(当涉及到订单时,我需要为同一订单 ID 获取两个可观察对象)。

QuietOran - 这是我尝试过的。我知道这很可怕,但我现在很迷失……

onValidateRequest(requestId: number) {

  this.requestService.getUserRequest$(this.requestId)
    .do(request => {
      this.validateRequest(request);
    })
    .concatMap(request => this.orderService.getOrdersForRequest$(request.id))
    .do(orders => {
      this.validateOrders(orders);
    })
    .concatMap(orders => {

      // Now, this is were I'm completely lost
      // I manage to get the request and the orders, but in this block, I need to get the client AND the products
      // and validate each one as I receive it
      // Then return something

    })
    .do(() => {
      // when I validate an element, if there's an error, I simple add it in an array. 
      // So when ALL the Observable above are completed, this function simply checks
      // if there's something in it
      this.checkForErrors();
    })
    .subscribe();

}

最佳答案

我将为您提供一些粗略的信息,您可以通过反馈进行完善,因为我不清楚您想要返回的数据的最终形状。希望这能为您指明正确的方向。

基本上,如果您希望将一个可观察的数据提供给另一个可观察的数据,那么您可以使用 switchmap 或其同类之一。如果您需要输入的值以及结果,那么只需将它们与 combineLatest 或类似的东西组合在一起即可。

console.clear();
function getUserRequest(requestId) {
  return Rx.Observable.of({ id: 1, subject: 'a', orderIds: [10, 20] })
  	.delay(500).take(1);
}
function getOrdersForRequest(requestId) {
  return Rx.Observable.of([
    { id: 10, clientId: 100, productIds: [ 1000 ] },
    { id: 20, clientId: 200, productIds: [ 1001, 1002 ] }
  ]).delay(200).take(1);
}
function getClientForOrder(orderId) {
  let client;
  switch(orderId) {
    case 10:
      client = { id: 100, name: 'Bob' };
      break;
    case 20:
      client = { id: 200, name: 'Alice' };
      break;
  }
  return Rx.Observable.of(client).delay(200).take(1);
}
function getProductsForOrder(orderId) {
  let products;
  switch(orderId) {
    case 10:
      products = [{ id: 1000, name: 'p1', price: 1 }];
      break;
    case 20:
      products = [
        { id: 1001, name: 'p1', price: 2 },
      	{ id: 1002, name: 'p1', price: 3 }
      ];
      break;
  }
  return Rx.Observable.of(products).delay(200).take(1);
}

Rx.Observable.of(1)
  .switchMap(id => Rx.Observable.combineLatest(
    getUserRequest(id),
    getOrdersForRequest(id)
      .switchMap(orders => Rx.Observable.combineLatest(
          Rx.Observable.of(orders),
          Rx.Observable.combineLatest(...orders.map(o => getClientForOrder(o.id))),
          Rx.Observable.combineLatest(...orders.map(o => getProductsForOrder(o.id)))
        )
      ),
    (userRequest, [orders, clients, products]) =>
        ({ userRequest, orders, clients, products })
  )
).subscribe(x => { console.dir(x); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>

现在我按类别对结果进行了扁平化。您可能希望它们嵌套或类似的东西。这只是一个粗略的过程,因此请根据需要提供反馈。

关于javascript - 在 Angular 2+ 中按顺序订阅可变数量的 Observable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48327227/

相关文章:

javascript - 将内联 JavaScript 放在头部

javascript - 缩放图像和 HTML5 视频以适合具有相同高度的行

javascript - 如果它们的 Prop 不同,如何流动类型组件 Prop 和getDerivedStateFromProps?

angular - ng2-dragula [dragula](angular2 拖放)- *ngFor with [dragulaModel] 属性不起作用

javascript - 如何在 Chrome 的性能分析器中调试匿名 JavaScript 函数?

reactjs - 如何测试包含在 withRouter 中的 React 组件的回调?

javascript - 如何通过 html 标签将每一行换行到文本区域内?

javascript - 使用基本的 jQuery 按季度划分年份

angular - 在 Electron 中关闭MatDialogRef

ngFor 循环中点击的 div 的 Angular Return id