简体   繁体   English

使用 RXJS switchMap 仅取消特定的待处理 HTTP 请求

[英]Cancel only specific pending HTTP request with RXJS switchMap

I am trying to solve the following use case, but the more I read the more confused I get.我正在尝试解决以下用例,但我读的越多,我就越困惑。 Perhaps someone could show me the right direction.也许有人可以告诉我正确的方向。

Let's say I have some sort of javascript service that is called by some client and triggers a calculation via REST endpoint on a backend server.假设我有某种 javascript 服务,该服务由某个客户端调用,并通过后端服务器上的 REST 端点触发计算。 The necessary HTTP request is implemented using RXJS observables.必要的 HTTP 请求是使用 RXJS observables 实现的。 Assume that the calculation is done based on seperate domain entites - I will come back to this in a moment.假设计算是基于单独的域实体完成的——我稍后会回到这一点。

The javascript service may be called multiple time within a short period of time. javascript服务可能在短时间内被多次调用。 Sometimes the interval between the service invocations may be shorter than the time for the relating HTTP response.有时服务调用之间的间隔可能比相关 HTTP 响应的时间短。 As service invocation may occur for the same domain entity (but with modified data), flying HTTP requests for a domain entity that another calculation has been triggered recently should be cancelled.由于同一域实体(但数据已修改)可能会发生服务调用,因此应取消最近触发了另一个计算的域实体的飞行 HTTP 请求。

I know that I can use switchMap to "switch to a new inner observable" while the pending inner observable is cancelled.我知道我可以使用 switchMap 来“切换到新的内部 observable”,而挂起的内部 observable 被取消。

import { of, Subject } from "rxjs";
import { delay, switchMap, tap } from "rxjs/operators";

const outer = new Subject();

const inner = (x) => of("Calculation Result " + JSON.stringify(x)).pipe(
  tap(() => console.log('Begin Calculation', x)),
  delay(1000)
);

function startCalc(x) {
  outer.next(x);  
}

outer.pipe(switchMap((x) => inner(x))).subscribe(x => console.log(x));

startCalc({id: 'A', data: 1}); // Entity A
startCalc({id: 'B', data: 1});
startCalc({id: 'A', data: 3}); // Entity A again
startCalc({id: 'C', data: 1});
startCalc({id: 'D', data: 1});

This snippet prints Calculation Result {"id": "D", "data": 1} to the console.此代码段将Calculation Result {"id": "D", "data": 1}打印到控制台。 I understand that all the invocations (for entities A, B, A, and C) are cancelled as the last invocation is triggered before the calculation response is emitted by the inner observable.我知道所有调用(对于实体 A、B、A 和 C)都被取消,因为在内部 observable 发出计算响应之前触发了最后一次调用。

How can I achieve that the outer observable emits我怎样才能实现外部可观察的发射

Calculation Result {"id": "B", "data": 1}
Calculation Result {"id": "A", "data": 3}
Calculation Result {"id": "C", "data": 1}
Calculation Result {"id": "D", "data": 1}

with the first invocation for entity A being cancelled as a second invocation for the same entity has been taken place before the relating calculation result for the first invocation has been returned.取消对实体 A 的第一次调用,因为在返回第一次调用的相关计算结果之前已经发生了对同一实体的第二次调用。

Any help is really appreciated.非常感谢任何帮助。

You could use the operator groupBy to split the outer observable into multiple observables based on the id property.您可以使用运算符groupBy根据 id 属性将外部可观察对象拆分为多个可观察对象。 And then apply the switchMap to those splitted Observables.然后将 switchMap 应用到那些拆分的 Observable 上。

It'd be something like this.会是这样的。

outer.pipe(
  groupBy((item) => item.id), // splits main source into multiple entityObs
  mergeMap( //executes all those splitted observables in parallel
    (entityObs) => entityObs.pipe(switchMap((x) => inner(x))) //switch on each entityObs.
  )
)
.subscribe((x) => console.log(x));

Cheers干杯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM