TypeScript:按顺序发送多个HTTP请求Angular2

时间:2018-03-02 13:54:57

标签: javascript angular typescript observable subscribe

我正在向Web API发送请求,并根据第一次API返回的返回值再次向同一API发送请求。然后我试图将Web API组件映射到一个类,但map方法不等待第二次调用返回。请帮助我们在成功返回两个电话后如何映射?

以下是我的代码

getOrderDetail(orderId: string): Observable<OrderHeader> {

return this.svc.wCWebClientServiceGetOrderDetails({ _orderId: orderId })
  .do(order => {
    order.SalesLines.forEach(saleLine => {
      if (saleLine.RelatedOrders !== undefined && saleLine.RelatedOrders.length > 0) {
        saleLine.RelatedOrders.forEach(relatedOrder => {
          this.svc.wCWebClientServiceGetOrderDetails({ _orderId: relatedOrder.TransId })
            .subscribe(relOrder => {
              //debugger;
              relOrder.SalesLines.forEach(relLine => {
                order.SalesLines.push(relLine);
              });
            })
        });
      }
    })
  })
  //.do(order => console.log('Received order', order))
  .map(order => this.transformOrder(order));

}

3 个答案:

答案 0 :(得分:1)

您可以使用名为 MergeMap 的RxJs运算符(也称为 flatMap )来映射/迭代Observable值。

import { Component } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { mergeMap } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: 'app/app.component.html'
})
export class AppComponent {
  homeworld: Observable<{}>;
  constructor(private http: HttpClient) { }

  ngOnInit() {
    this.homeworld = this.http.get('/api/people/1').pipe(
      mergeMap(character => this.http.get(character.homeworld))
    );
  }
}

因此,在我们获得homeworld的示例中,我们在我们的角色Observable流中返回一个Observable。这在Observable中创建了一个嵌套的Observable。 mergeMap运算符通过订阅并从内部Observable中提取值并将其传递回父流来帮助我们。

有关详情,您可以查看此博客:Angular Multiple HTTP Requests with RxJS

答案 1 :(得分:0)

这个flatMap运算符与forkJoin一起应该可以解决问题..

getOrderDetail(orderId: string): Observable<OrderHeader> {
    return this.svc.wCWebClientServiceGetOrderDetails({ _orderId: orderId })
    .flatMap(order => {
        order.SalesLines.forEach(saleLine => {
            let observables:Array<Observable<any>> = [];

            if ( /* Your predicate */ ) {
                saleLine.RelatedOrders.forEach(relatedOrder => {
                    observables.push(this.svc.wCWebClientServiceGetOrderDetails({ _orderId: relatedOrder.TransId }));
                });
            }

            // Perform the calls to retrieve order details asynchronously
            return Observable.forkJoin(observables).map((results:Array<any>) => {
                 results.forEach(relOrder => {
                    relOrder.SalesLines.forEach(relLine => {
                        order.SalesLines.push(relLine);
                    });
                 });
            });
        });
    })
    // Perform your final transformation on the results
    .map(order => this.transformOrder(order));
}

答案 2 :(得分:0)

我相信您正在寻找的是expand方法。

以下是我自己的一个例子:

VA7B(params: VA7B, accountList: any, balanceSequenceList: string[], docNumber: string) {
        const sequenceList = [...balanceSequenceList];

        // Função que define o código do balanço financeiro para a conta atual
        const setBalanceCode = () => {
            params.balance.accountNumberRecalled = StringFormat.padLeft('', 7);
            params.balance.demoAccountNumber = sequenceList[0];
            sequenceList.shift();
        };

        const total = accountList.reduce((acc: any, curr: any) => acc + curr.length, 0);

        // Função que realiza a requisição RESTFUL ao servidor.
        const post = (account: string): Observable<VA7BResponse> => {
            const payload: PayLoad<VA7B> = new PayLoad<VA7B>();

            params.balance.document.number = docNumber;
            payload.obj = params;
            payload.obj.balance.accountData = account;

            payload.url = 'url_VA7B';
            payload.result = VA7BResponse;
            payload.hasCripto = this.hasCripto;
            payload.criptoFields = [{ balance: Object, document: Object, number: String }];
            payload.decriptoFields = [];

            return this.baseService.POST<VA7B>(payload);
        };

        setBalanceCode();

        // O método 'expand' é responsável por chamar a função REST recursivamente, caso ainda hajam contas a ser importadas.
        return post(accountList[0][0])
            .expand((res: VA7BResponse) => {
                params.balance.accountNumberRecalled = accountList[0][0].substr(-25, 7);
                accountList[0].shift(); // Após ser importado, o primeiro item é removido da lista.

                // Caso a primeira lista esteja vazia, remove a lista e passa para o próximo demonstrativo.
                if (accountList[0].length === 0) {
                    accountList.shift();
                    setBalanceCode();

                    // Caso não hajam mais balanços, encerra o processo e retorna.
                    if (accountList.length === 0) {
                        return Observable.empty();
                    }
                }

                return post(accountList[0][0]);
            }).take(total);
    }