有没有办法在flatMap
或concatMap
操作完成之前取消/删除单个可观察对象?
我目前有一个可观察的触发API请求的UI操作,我使用flatMap
:
actionsFromUI.flatMap(a => http.request("blah?id=" + a.id))
然后订阅渲染结果。一个非常好的属性是,如果我取消订阅,所有正在进行的API请求都会自动取消。我不想打破这个。
现在,我想支持可以取消特定正在进行的请求的UI操作。 UI操作可以触发特定ID的API请求,然后后续UI操作可以取消该ID的API请求。
我希望这个虚拟代码能够说明我尝试做的事情:
let actions = [
{ action: "start", id: 1 },
{ action: "start", id: 2 },
{ action: "start", id: 3 },
{ action: "cancel", id: 1 },
{ action: "start", id: 4 },
{ action: "cancel", id: 3 },
{ action: "start", id: 1 }
];
Observable.from(actions)
.flatMap(a => {
if (a.action === "start") {
return http.request("blah?id=" + a.id);
} else if (a.action === "cancel") {
// ???
}
})
.subscribe(response => {
console.log(response);
});
答案 0 :(得分:2)
是的,有办法做到这一点。
您可以使用takeUntil
运算符。
有人会这样想:
// actions - observable of user actions, each action has id field
// cancelActions - observable of action cancelations each has id of action to cancel
// doRequest - function that starts request and returns observable
const results = actions.flatMap(
action => doRequest(action)
.takeUntil(
cancelActions.filter(cancel => cancel.id === action.id)
)
);
https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/takeuntil.md
答案 1 :(得分:1)
这是一种方法。
从可观察的原始数据开始:
let actions = Observable.from([
{ action: "start", id: 1 },
{ action: "start", id: 2 },
{ action: "start", id: 3 },
{ action: "cancel", id: 1 },
{ action: "start", id: 4 },
{ action: "cancel", id: 3 },
{ action: "start", id: 1 }
]);
然后我创建了两个函数来模拟数据的处理和取消:
let start = n =>
Observable
.of(`Finished ${n}`)
.delay(1000);
let cancel = n =>
Observable
.of(`Cancelled ${n}`);
我让start
需要1秒钟来处理,cancel
立即返回。
然后我运行了这个查询:
let query =
actions
.groupBy(x => x.id)
.map(gx =>
gx
.map(x => x.action === "start"
? start(x.id)
: cancel(x.id))
.switch())
.mergeAll();
这给了我这个结果:
Cancelled 1 Cancelled 3 Finished 2 Finished 4 Finished 1
我认为这就像你想要的那样。
如果有人能为我翻译成JS,我会很感激。