Rx(JS)有选择地取消订阅flatMap中的observable

时间:2016-07-13 09:20:27

标签: reactive-programming rxjs

有没有办法在flatMapconcatMap操作完成之前取消/删除单个可观察对象?

我目前有一个可观察的触发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);
    });

2 个答案:

答案 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,我会很感激。