使用以前的observable中的最新值切换到新的observable作为输入

时间:2018-05-31 07:21:34

标签: rxjs

我有一个请求对象流:

let request$ = new Subject();

我有一个函数,它接受一个请求对象和当前的app状态对象,并返回一个新的状态对象流:

function stream(request, state) {
    // Return a cold Observable of new state objects
}

当发出第一个请求时,我想调用stream并传入该请求和一个初始状态对象,并开始处理它返回的状态。

之后的一段时间,会发出第二个请求。第一个流需要停止并替换为通过再次调用stream创建的新流,传递第二个请求以及从第一个流发出的最新状态。

我觉得可能scan使用更高阶的流可以做到但我被困在这里:

request$.pipe(
    scan((state$, request) => {
        let previousState = ???
        return stream(request, previousState);
    }, of(initialState)),
    switchAll()
)

编辑 - 示例

在现实生活中,stream函数建立与服务器的websockets连接,在请求中发送部分请求和状态参数,然后在从服务器接收消息时发出新的状态对象。

为简化示例,假设requeststate只是数字,而stream函数只是重复添加requeststate,每秒一个结果:

function stream(request, state) {
    return interval(1000).pipe(
        map(i => state + (i+1) * request)
    );
}
// e.g. stream(2, 10) will emit 12, 14, 16, 18, ...

所需的输出是:

initialState = 10

request$       2------------5-----------------
stream(2, 10)  --12--14--16-|
stream(5, 16)               --21--26--31--36--
...
output         --12--14--16---21--26--31--36--

请注意,在5请求发出时,5和最新状态16都需要构建下一个流。

2 个答案:

答案 0 :(得分:3)

一种简单的方法是使用defer创建一些可以存储最新状态的按订阅状态:

const source = defer(() => {
    let lastState = initialState;
    return request$.pipe(
        switchMap(request => stream(request, lastState)),
        tap(state => lastState = state)
    );
});

以这种方式使用,defer将确保source的每个订阅都有自己的lastState

答案 1 :(得分:1)

scan运算符采用具有先前状态和当前值的函数,initialState也不应为Observable

我认为这应该会更好:

request$.pipe(
    scan((previousState, request) => {
        return stream(request, previousState);
    }, initialState),
    switchAll()
)