使用SwitchMap()处理取消先前的请求

时间:2018-12-14 13:18:28

标签: angular rxjs angular2-observables

我的Angular2应用程序中有一个功能,用户可以选择各种过滤器来过滤在网格视图中返回的数据。这种获取和过滤数据的工作。但是,我需要找到一种方法-最好使用RxJS和类似switchMap()的方法在更改过滤器选择时取消请求-以便只有最近的请求才能通过网络。

我一直很难使它起作用。因此,我首先需要确定当前的配置是否实际上是可观察到的RxJS,然后确定在何处插入switchMap()之类的运算符。

这是我的代码的样子:

private sendRequest = _.debounce((languageFilter, locationFilter, zipFilter, firstNameFilter, lastNameFilter, branchFilter) =>
{
    this.filtersService.getByFilters(
        this.page - 1, this.pagesize, this.currentStage, this.language = languageFilter, this.location = locationFilter,
        this.zipcode = zipFilter, this.firstName = firstNameFilter, this.lastName = lastNameFilter,
        this.branch = branchFilter,
        (resRecordsData) => {
            this.records = resRecordsData;
         });
 }, 200);

public onFilterReceived(values)
{
    let languageFilter = [];
    let locationFilter = [];
    let zipFilter = [];
    let firstNameFilter = [];
    let lastNameFilter = [];
    let branchFilter = [];

     this.route.params.subscribe(
         (params: any) => {
             this.page = params['page'];
             this.pn_zip_e = params['pn_zip.e'];
             this.pn_firstName_e = params['pn_firstName.e'];
             this.pn_lastName_e = params['pn_lastName.e'];
             this.pn_location_e = params['pn_location.e'];
             this.pn_branch_e = params['pn_branch.e'];
             this.pn_language_e = params['pn_language.e'];
         }
     );

     this.pn_language_e === "1" ? languageFilter = values['language'] : languageFilter = [];
     this.pn_location_e === "1" ? locationFilter = values['location'] : locationFilter = [];
     this.pn_zip_e === "1" ? zipFilter = values['zip'] : zipFilter = [];
     this.pn_firstName_e === "1" ? firstNameFilter = values['firstName'] : firstNameFilter = [];
     this.pn_lastName_e === "1" ? lastNameFilter = values['lastName'] : lastNameFilter = [];
     this.pn_branch_e === "1" ? branchFilter = values['branch'] : branchFilter = [];

     this.sendRequest(languageFilter, locationFilter, zipFilter, firstNameFilter, lastNameFilter, branchFilter);
};

从我的filterService调用的getByFilters()函数如下所示:

public getByFilters(page, pagesize, stage?, language?, location?, zipcode?, firstName?, lastName?, branch?, fn?: any)
{
    return this.apiService.get({
      req: this.strReq, reqArgs: { page, pagesize, stage, language, location, zipcode, firstName, lastName, branch }, callback: fn });
}

依次在我们的中央请求控制器服务(apiService)中调用GET请求,如下所示:

public get(args: {
    req: string,
    reqArgs?: any,
    reqBody?: any,
    callback?: IRequestCallback
}): Observable<Response>
{
    args['reqType'] = 'get';
    return this.runHttpRequest(args);
}

一旦收到响应,便将其分配给“ this.records”,然后在我的视图中使用它遍历“ this.records.data”(它是一个数组),以将记录打印到屏幕上。

因此,从我上面的代码中,此行是我获取响应并将其分配给“ this.records”的地方:

  this.records = resRecordsData;

所以,我的第一个问题是,如何确定这里是否有可观察到的RxJS,然后如何使用类似switchMap()的运算符来处理取消先前的过滤器请求?

我尝试了这个,但是没有用。我的猜测是语法不正确:

private sendRequest = _.debounce((languageFilter, locationFilter, zipFilter, firstNameFilter, lastNameFilter, branchFilter) =>
{
    this.streamFiltersService.getByFilters(
        this.page - 1, this.pagesize, this.currentStage, this.language = languageFilter, this.location = locationFilter,
        this.zipcode = zipFilter, this.firstName = firstNameFilter, this.lastName = lastNameFilter,
        this.branch = branchFilter,
         (resRecordsData) => {
            resRecordsData.switchMap((res) => {
                this.records = res;
            });
            console.log('records: ', this.records);
         });
 }, 200);

首先,为了确保我正在树立正确的树,我想有一种方法来确定我在这里的响应是否实际上是可观察到的RxJS。而且,如果没有,找到一种将其转换为一个的方法,这样我就可以在其上使用switchMap()

1 个答案:

答案 0 :(得分:0)

我为switchMap创建了实例,并使用reactForm创建了两个输入。可以使用fromEvent(inputElement,'change')代替this.inputElement.valueChanges

// We want combine of all lastest values.
combineLatest(
  // We merge default name with observable of name input.
  merge(
    of('default'),
    // From input we want to be inform after 200ms debounce and if they have change.
    this.name.valueChanges.pipe(debounceTime(200), distinctUntilChanged())
    ),
  // We merge default choice with observable of choice input.
  merge(
    of('value 1'),
    this.choice.valueChanges.pipe(debounceTime(200), distinctUntilChanged())

  )
).pipe(map(e => {
  // We construct the request payload
  return {
    name: e[0],
    choice: e[1]
  }
  // Ignore combined default value, ask api and subscribe to answer.
})).pipe(skip(1), switchMap(e => this.myApi(e))).subscribe(console.log);

为了确保理解每个步骤,我强烈建议您按组成变量对其进行拆分,并console.log每个订阅的流。示例:

可观察的输入

this.name.valueChanges.pipe(debounceTime(200), distinctUntilChanged()).subscribe(console.log)

在经过200ms的反跳后,将输出您当前的输入值,如果该值与先前发出的值相比有变化。

可观察到的具有默认值的输入

merge(
    of('default'),
    this.name.valueChanges.pipe(debounceTime(200), distinctUntilChanged())
),

我们将立即默认值与输入流上发出的将来值合并。

最新组合

从先前的合并合并中,我们希望将每个输入的最新发射值合并为单个流。

地图

.pipe(map(e => {
  // We construct the request payload
  return {
    name: e[0],
    choice: e[1]
  }
  // Ignore combined default value, ask api and subscribe to answer.
})

因为CombineLatest将创建作为参数提供的最新发射流的数组。我们希望将此数组映射到api的真实有效负载对象。

switchMap

switchMap(e => this.myApi(e)))

您拥有了有效载荷(通过前面描述的地图生成),将其转换为新的可观测值。现在,您可以简单地进行订阅,并且您将神奇地根据输入值的集合获得API的答案,并自动取消不再相关的先前请求。

live sample


要基于路径Params,您可以执行以下操作。

  ngOnInit() {
    // From url params change, we map output with default value.
    const routeParams$ = this.route.params.pipe(map(params => {
      return {
        user: '',
        choice: '',
        ...params
      };
    }));
    // Uncomment me to see it in action.
    // routeParams$.subscribe(console.log);
    // Transform this payload to http request and subscribe to it.
    routeParams$.pipe(switchMap(e => this.myApi(e))).subscribe(console.log);
  }

Live sample