Rest RxJs:从服务器请求列表,使用值,当我们';你几乎失去了价值

Rest RxJs:从服务器请求列表,使用值,当我们';你几乎失去了价值,rest,http,rxjs,observable,rxjs5,Rest,Http,Rxjs,Observable,Rxjs5,我正在从RESTAPI获取一个项目列表。用户通过单击与每个项目进行交互,当只有(比如)两个未使用的项目时,我想重复请求以获取更多项目。我正试图使用一种适当的面向RxJs(5)流的方法来实现这一点 比如说: var userClick$ = Observable.fromEvent(button.nativeElement, 'click'); var needToExtend$ = new BehaviorSubject(1); var list$ = needToExtend$

我正在从RESTAPI获取一个项目列表。用户通过单击与每个项目进行交互,当只有(比如)两个未使用的项目时,我想重复请求以获取更多项目。我正试图使用一种适当的面向RxJs(5)流的方法来实现这一点

比如说:

var userClick$ = Observable.fromEvent(button.nativeElement, 'click');

var needToExtend$ = new BehaviorSubject(1);

var list$ = needToExtend$
            .flatMap( () => this.http.get("http://myserver/get-list") )
            .flatMap( x => x['list'] );

var itemsUsed$ = userClick$.zip(list$, (click, item) => item);
itemsUsed$.subscribe( item => use(item) );
然后,在必要时触发重新加载:

list$.subscribe(
    if (list$.isEmpty()) {
        needToExtend$.next(1);
    }
)
最后一点是错误的,手动重新触发似乎不是很“面向流”,即使它确实按预期工作。有什么想法吗


这与API类似,但我不能假设API返回的列表的长度,我希望在列表完全使用之前重新请求。这里的解决方案感觉有点太聪明了。一定有更可读的方法,对吗?

像这样的东西怎么样:

const LIST_LIMIT = 3;
userClick$ = Observable.fromEvent(button.nativeElement, 'click');
list$ = this.http.get("http://myserver/get-list").map(r => r.list);

clickCounter$ = this.userClick$.scan((acc: number, val) => acc + 1, 0);

getList$ = new BehaviorSubject([]);

this.getList$
    .switchMap(previousList => this.list$)
    .switchMap(list => this.clickCounter$, (list, clickCount) => { return {list, clickCount}; })
    .filter(({list, clickCount}) => clickCount >= list.length - LIST_LIMIT)
    .map(({list, clickCount}) => list)
    .subscribe(this.getList$);
这里的逻辑是定义一个列表getter流和一个触发它的信号

首先,该信号使switchMap获取一个新列表,然后将该列表输入另一个switchMap,该switchMap重新订阅一个点击计数器。组合两个流的结果并将其馈送到过滤器,只有当单击计数大于或等于列表长度减3(或任何您想要的值)时才会发出。然后信号被订阅到整个流中,以便它自己重新触发

编辑:最大的缺点是需要在副作用中设置列表值(用于显示),而不是在订阅或异步管道中。您可以重新排列它并进行多播,但:

const LIST_LIMIT = 3;
userClick$ = Observable.fromEvent(button.nativeElement, 'click');
list$ = this.http.get("http://myserver/get-list").map(r => r.list);

clickCounter$: Observable<number> = this.userClick$.scan((acc: number, val) => acc + 1, 0).startWith(0);

getList$ = new BehaviorSubject([]);

refresh$ = this.getList$
        .switchMap(list => this.clickCounter$
                               .filter(clickCount => list.length <= clickCount + LIST_LIMIT)
                               .first(), 
            (list, clickCount) => list)
        .switchMap(previousList => this.list$)
        .multicast(() => this.getList$);

this.refresh$.connect();
this.refresh$.subscribe(e => console.log(e));
const LIST\u LIMIT=3;
userClick$=Observable.fromEvent(button.nativeElement,'click');
list$=this.http.get(“http://myserver/get-list)地图(r=>r.list);
clickCounter$:Observable=this.userClick$.scan((acc:number,val)=>acc+1,0)。开始第(0)步;
getList$=新行为主体([]);
刷新$=this.getList$
.switchMap(列表=>this.clickCounter$
.filter(单击计数=>list.length列表)
.switchMap(previousList=>this.list$)
.multicast(()=>this.getList$);
此.refresh$.connect();
this.refresh$.subscribe(e=>console.log(e));

这种方式有一些优点,但可能不太“可读”。各部分大致相同,但您先转到计数器,然后让其进入列表获取的开关。然后您将其多播以重新启动计数器。

我不清楚您是如何跟踪获取下一组项目的,因此我将假设这是某种形式的寻呼,以获取我的答案。我还假设您不知道总数项目数量

console.clear();
常数pageSize=5;
常数pageBuffer=2;
常量数据=[…数组(17).keys()]
函数getData(第页){
const begin=pageSize*page
const end=开始+页面大小;
返回Rx.Observable.of(数据片(开始,结束));
}
常数点击=接收可观察间隔(400);
咔哒声
.scan(计数=>++计数,0)
.do(()=>console.log('click'))
.map(计数=>{
常量页面=数学楼层(计数/页面大小)+1;
const total=页面*页面大小;
返回{total,page,count}
})
.filter(x=>x.total-pageBuffer===x.count)
.startWith({page:0})
.switchMap(x=>getData(x.page))
.takeWhile(x=>x.length>0)
.订阅(
x=>{console.log('next:',x);},
x=>{console.log('error:',x);},
()=>{console.log('completed');}
);

可以多次单击项目吗?这有关系吗?组件模板代码/what use()在这里可能会有帮助。我想这样做,但这个要求阻碍了我:“我不能假设API返回的列表的长度”,可能我误解了这一点,但我认为这意味着返回数组的长度基本上是随机的,所以恒定的页面大小不会work@bryan60说得好。我第一次读它的时候,我以为他们指的是物品的总数,但我想你可能是对的。布莱恩说得对,我们不知道返回的清单的长度(可能会有所不同),但谢谢你花时间写下这个好的回复。无论如何,这是一个教育性的回答。谢谢!这让我找到了一个有效的解决方案。一个小提示:我认为这个解决方案在请求一个新列表并丢弃旧列表的其余部分之前并没有完全使用完每个列表。我只是在这里删除了列表限制,然后做了一个初始请求开始时是st,并将其与刷新列表合并。很高兴它完成了任务。这是一个有趣的小练习。我加入了列表限制,因为我认为目标是在原始列表完全用完之前请求新列表,但我可能误解了