我有一个请求对象流:
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连接,在请求中发送部分请求和状态参数,然后在从服务器接收消息时发出新的状态对象。
为简化示例,假设request
和state
只是数字,而stream
函数只是重复添加request
到state
,每秒一个结果:
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
都需要构建下一个流。
答案 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()
)