Angular 如何正确使用exhaustMap-如何在发送另一个请求之前等待服务调用返回

Angular 如何正确使用exhaustMap-如何在发送另一个请求之前等待服务调用返回,angular,rxjs,angular7,Angular,Rxjs,Angular7,我使用一个按钮来initialiseGrid()。在通话过程中,如果不禁用按钮,我希望等待第一个响应返回,然后触发第二个请求,或者(即使触发多个请求)按照请求发生的确切顺序处理响应。实际上,我尝试使用一些rxjs操作符而不是map,但我很确定我没有正确使用它们 于2020年7月20日更新: 我想排气图是正确的操作员使用。我应该如何在query或fetch方法中使用它 请在下面找到我的代码: APs.service.ts public query(token: string, tableName:

我使用一个按钮来
initialiseGrid()
。在通话过程中,如果不禁用按钮,我希望等待第一个响应返回,然后触发第二个请求,或者(即使触发多个请求)按照请求发生的确切顺序处理响应。实际上,我尝试使用一些rxjs操作符而不是
map
,但我很确定我没有正确使用它们

于2020年7月20日更新: 我想排气图是正确的操作员使用。我应该如何在
query
fetch
方法中使用它

请在下面找到我的代码:

APs.service.ts

public query(token: string, tableName: string, state: any): void {
    console.log("state in query", state);
    this.fetch(token, tableName, state)
        .subscribe((x: any) => {
            console.log("response data", this.data);
            super.next(x);
            this.isLoading = false;
            this.mediatorService.sendMessage("APsRefreshed");
        },
            (err: any) => {
                console.log("err", err);
                this.isLoading = false;
            }
        );
}

public fetch(token: string, tableName: string, state: any): Observable<any> {
    let queryStr = `${toODataString(state)}&$count=true`;
    queryStr = queryStr.replace(/('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')/ig, function (x) {
        return x.substring(1, x.length - 1);
    });
    queryStr = queryStr.replace(/substringof\((.+),(.*?)\)/, "contains($2,$1)");
    const regex = /T00:00:00\.000Z/gi;
    const noTimeZoneQueryStr = queryStr.replace(regex, '');

    let fetchCallResult = this.http
        .get(`${this.BASE_URL}` + `/` + token + `${tableName}&${noTimeZoneQueryStr}`)
        .pipe(
            map((response: any) => ((<any>this.data) = {
                data: response['value'],
                total: /*response['value'].length*/parseInt(response['@odata.count'], 10)
            }
            )),
        //tap(() => this.isLoading = false)
    );
    return fetchCallResult;
}
APs.template.html

<kendo-grid #gridView
            [data]="gridViewAPs | async"
            [loading]="APsService.isLoading"
            ...
>


提前谢谢。

当我需要控制执行顺序,特别是http调用时,我使用一个高阶映射操作符

  • concatMap(以串行方式进行调用)
  • mergeMap(以并行方式进行调用)
  • switchMap(发出呼叫,但如果有新请求,则忽略(取消订阅)上一个呼叫)
  • exhaustMap(进行调用并忽略任何新请求,直到前一个调用返回)
  • 在这里可以找到有关上述内容的优秀资源

    下面是您的代码的草稿,它经过重构以串行方式调用(我假设您的按钮单击是一个流,映射操作符构成您的查询输入)。用上述任何操作符替换concatMap,以获得http调用所需的顺序

    this.btnCLick$ // 1. That's your button click stream
          .pipe(
            map(() => ({token, tableName, state})), // 2. Map all your inputs into one input object from where ever you want
            concatMap(({token, tableName, state}) => { // 3. This operator will wait for the previous call to complete to make the next call (like a Queue)
              let queryStr = `${this.toODataString(state)}&$count=true`;
              queryStr = queryStr
                .replace(/('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')/ig, 
                  function (x) {
                    return x.substring(1, x.length - 1);
                  }
                );
              queryStr = queryStr.replace(/substringof\((.+),(.*?)\)/, "contains($2,$1)");
              const regex = /T00:00:00\.000Z/gi;
              const noTimeZoneQueryStr = queryStr.replace(regex, '');
    
              return this.http // 4. This part will make the http calls based on your query
                .get(`${this.BASE_URL}` + `/` + token + `${tableName}&${noTimeZoneQueryStr}`)
                .pipe(
                  map((response: any) => ({
                      data: response['value'],
                      total: /*response['value'].length*/parseInt(response['@odata.count'], 10)
                    })
                  ),
                  //tap(() => this.isLoading = false)
                );
            })
          )
          .subscribe(({data, total}) => { // 5. ***When each http call comes back with a response, the subscription will be called
                console.log("response data", data);
                super.next({data, total});
                this.isLoading = false;
                this.mediatorService.sendMessage("APsRefreshed");
            },
                (err: any) => {
                    console.log("err", err);
                    this.isLoading = false;
                }
          );
    

    使用is实现,您不必担心禁用按钮…

    我在这里只能看到一个http调用,第二个调用应该在哪里?没错。我是指同一服务的第二次(第三次、第四次等)呼叫。谢谢您的回答。我试试看。按钮位于另一个组件中。因此,我无法直接访问按钮。如上所示,initialiseGrid()在ngOnInit()中调用,网格数据源绑定到服务。所以,我不能使用这个.btnCLick$.pipe
    this.btnCLick$ // 1. That's your button click stream
          .pipe(
            map(() => ({token, tableName, state})), // 2. Map all your inputs into one input object from where ever you want
            concatMap(({token, tableName, state}) => { // 3. This operator will wait for the previous call to complete to make the next call (like a Queue)
              let queryStr = `${this.toODataString(state)}&$count=true`;
              queryStr = queryStr
                .replace(/('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')/ig, 
                  function (x) {
                    return x.substring(1, x.length - 1);
                  }
                );
              queryStr = queryStr.replace(/substringof\((.+),(.*?)\)/, "contains($2,$1)");
              const regex = /T00:00:00\.000Z/gi;
              const noTimeZoneQueryStr = queryStr.replace(regex, '');
    
              return this.http // 4. This part will make the http calls based on your query
                .get(`${this.BASE_URL}` + `/` + token + `${tableName}&${noTimeZoneQueryStr}`)
                .pipe(
                  map((response: any) => ({
                      data: response['value'],
                      total: /*response['value'].length*/parseInt(response['@odata.count'], 10)
                    })
                  ),
                  //tap(() => this.isLoading = false)
                );
            })
          )
          .subscribe(({data, total}) => { // 5. ***When each http call comes back with a response, the subscription will be called
                console.log("response data", data);
                super.next({data, total});
                this.isLoading = false;
                this.mediatorService.sendMessage("APsRefreshed");
            },
                (err: any) => {
                    console.log("err", err);
                    this.isLoading = false;
                }
          );