我有一个由事件产生的图像列表流,如下所示:
const imageSrcs$ = Rx.Observable.fromEvent($('#clicker'), 'click')
.flatMap(() => this.imageService.getImagesForUser(userUid))
.scan((acc, cur) => acc.concat(cur), [])
.startWith([]);
imageService.getImagesForUser(userId)
从数据库中检索有限数量的图像并返回图像列表:
[
{
id: number,
timestamp: string,
...
},...
]
所以这个observable只接受该结果并将累加器(scan()
)应用于它。但是,getImagesForUser
还需要一个额外的参数startAt
,这是开始检索的时间戳。对于我的情况,这应该是observable返回的数组中最后一个图像的时间戳。
当然,我可以这样做:
lastTimestamp;
...
const imageSrcs$ = Rx.Observable.fromEvent($('#clicker'), 'click')
.flatMap(() => this.imageService.getImagesForUser(userUid, this.lastTimestamp))
.scan((acc, cur) => acc.concat(cur), [])
.startWith([])
.subscribe(list => this.lastTimestamp = list[list.length - 1].timestamp);
但这似乎并不像关注点的分离,我有兴趣知道我是否可以在一个可观察的情况下做到这一点。我认为这样的事情会起作用:
const imageSrcs$ = Rx.Observable.fromEvent($('#clicker'), 'click')
.startWith([])
.filter(val => Array.isArray(val))
.last()
.map(val => val[val.length - 1].timestamp)
.flatMap(startAt => this.imageService.getImagesForUser(userUid, startAt))
.scan((acc, cur) => acc.concat(cur), []);
但当然,它并不是因为点击事件被过滤掉了。
答案 0 :(得分:2)
我能想到的最简单的方法就是这样(这只是模拟你的用例,但我认为你会明白这一点):
function getImagesForUser(startAt) {
return Observable
.range(startAt * 5, 5)
.toArray();
}
const imageSrcs$ = Observable.defer(() => {
let startAt = 0;
return Observable.timer(0, 1000)
.flatMap(() => getImagesForUser(startAt))
.do(arr => startAt = arr[arr.length - 1]);
})
.scan((acc, cur) => acc.concat(cur), [])
.startWith([])
.subscribe(console.log);
最终,scan()
运算符也可以进入.defer()
回调。
而不是点击我正在使用Observable.timer(0, 1000)
。我不知道在没有使用Observable链之外的任何状态变量的情况下是否有更好的方法。