- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在尝试使用 TypeScript 和 rxjs 构建一个无限滚动的列表。也就是说,我希望应用程序从后端获取几页结果,然后在用户滚动到底部附近时获取更多结果。
我有一个 Observable,用 Observable.prototype.expand()
构建,这将给我所有结果,最终从服务器获取所有页面。但是由于 Observable 的性质,我不能暂停这个过程。一旦我订阅,它不可避免地会尽快获取所有结果。我需要一个不同的解决方案,以我需要的速度从结果流中提取结果。
事情变得更加复杂,因为我无法直接从 API 获取第二页,每个页面都包含我获取下一页所需的信息。回复看起来像这样:
interface GraphApiResponse {
data?: any[];
paging?: {
cursors: {
before: string,
after: string
},
next?: string,
previous?: string
};
}
paging.next
的存在表示还有另一页 paging.cursors.after
用于实际检索它。
我似乎无法弄清楚如何在不弄乱它的情况下实现它。然而,无限列表似乎是一个常见的问题,不太可能没有好的解决方案。我应该如何着手实现它,而不会使事情变得一团糟?
我的第一个想法是使用一个可迭代的 Promises,但是我不知道我会得到多少结果,迫使我构建一个无限的 Iterable<Promise<Response?>>
谁的 Promises 都将解析为 undefined
在某一点之后。然而,由于它是无限的,我无法正常迭代它(它会用 Promises 填充整个可用内存),实际上在结果处于那种形式时使用结果意味着在前一个的 resolve 函数中获得每个 Promise。
这个解决方案似乎可行,但随着我编写的每一行,它的可读性越来越差,而且越来越复杂。
在谷歌上搜索这个问题时,我发现了 a related SO question以及a GitHub issue on rxjs backpressure ,两者都包含 Ben Lesh 的代码片段,显然可以用来向 Observable 添加背压,遗憾的是,无论我尝试什么,我都无法让源 Observable 发射它的值比它生成它们的速度慢,它们总是被缓冲某处,这意味着网络请求无论如何都会发生。
来自 GitHub:
// this behavior subject is basically your "give me the next batch" mechanism.
// in this example, we're going to make 5 async requests back to back before requesting more.
const BATCH_SIZE = 5;
const requests = new BehaviorSubject(BATCH_SIZE); // start by requesting five items
// for every request, pump out a stream of events that represent how many you have left to fulfill
requests.flatMap((count) => Observable.range(0, count).map(n => count - n - 1))
// then concat map that into an observable of what you want to control with backpressure
// you might have some parameterization here you need to handle, this example is simplified
// handle side effects with a `do` block
.concatMap(() => getSomeObservableOfDataHere().do(stuffWithIt), (remaining) => remaining)
// narrow it down to when there are no more left to request,
// and pump another batch request into the BehaviorSubject
.filter(remaining => remaining === 0)
.mapTo(BATCH_SIZE)
.subscribe(requests);
来自 StackOverflow:
// start with 5 values
const controller = new Rx.BehaviorSubject(5);
// some observable source, in this case, an interval.
const source = Rx.Observable.interval(100)
const controlled = controller.flatMap(
// map your count into a set of values
(count) => source.take(count),
// additional mapping for metadata about when the block is done
(count, value, _, index) => {
return { value: value, done: count - index === 1 };
})
// when the block is done, request 5 more.
.do(({done}) => done && controller.next(5))
// we only care about the value for output
.map(({value}) => value);
// start our subscription
controlled.subscribe(x => {
console.log(x)
});
我对此可能是错误的,但在我看来,一旦我订阅了一个 Observable,它就会尽可能快地产生它的值,没有办法减慢它的速度,所以这可能不是一个解决方案。
似乎ixjs旨在解决我的问题,但是该存储库已经很长时间没有更新了。显然有 a reimplementation in TypeScript ,但是这似乎处于早期开发阶段并且没有很好地记录 jet。
对于实际上非常简单的问题,我宁愿不依赖于少数人使用的框架。
我在网上搜索了 TypeScript(使用 Angular)中无限滚动列表的实现。我当前的方法是拥有一个服务,该服务提供一个对象,可用于获取所有结果。然后我有一个显示它们的组件。替代品似乎是 doing the checking for scroll position right in the service that queries the backend , 或 having the component fetch a new Observable from the backend service when the user scrolls .
这两种解决方案都会迫使我混合使用目前整齐分开的代码。我更希望让服务返回一些东西,我可以将这些东西提供给组件,而组件不必知道网络请求,或者服务不必知道滚动位置。
最佳答案
我建议您查看 mergeScan
运算符代替。看起来它可能很适合这里。
MergeScan
类似于 expand
运算符,因为它将来自先前请求的数据作为累加器返回,但与 expand
不同直到时间结束才继续运行。
基本上假设您有一个函数makeRequest(params)
,它接受一个请求并返回一个Observable
,最终解析为一个响应,一个流表示滚动事件,我们将调用 fetchMore$
,您可以像这样创建按需获取服务:
// This is abstracted as a simple "fetch" concept but in reality should
// be hooked up to your scroll handler, properly debounced etc.
this.fetchMore$
.mergeScan(
// Make the request
(acc, _) => makeRequest(acc.paging.next ? acc.paging.cursors.after : ''),
{paging: {}}, // Initial request body
1 // Maximum concurrency, i.e. how many requests can be in flight at once
)
.pluck('data')
.subscribe(data => {/*Do something with the data*/});
我将并发设置为 1,因为虽然您可能有多个请求在进行中,但目前无法保证顺序,因此如果用户滚动得非常快,结果可能是 acc 不同步,而对于并发度为 1 时,数据将始终有序。
关于typescript - 使用 rxjs5 在 typescript 中构建无限滚动列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45383857/
如标题所示,ans_list是一个答案列表,ans_index是一个数字(答案在词汇表中的索引,但与atm无关) 这里生成的 tree.anslist 是什么? (例如,仅针对第一个),忽略迭代。 f
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将具有一个元素的东西拿走。 这与 How do I “flatte
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将带有一个元素的东西拿走。 这与 How do I “flatte
这个问题已经有答案了: Convert nested list to 2d array (3 个回答) 已关闭 7 年前。 java中有没有快捷方式可以转换 List> 到 String[][] ?
我在排序时遇到问题 List> 。我创建了一个自定义比较器,在其中编写了对数据进行排序的代码。 public class CustomComparator implements Comparator
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Java Generics: Cannot cast List to List? 我只是想知道为什么下面的java代
试图想出一个 LINQy 方法来做到这一点,但我什么也没想到。 我有一个对象列表<>,其中包含一个属性,该属性是逗号分隔的字母代码列表: lst[0].codes = "AA,BB,DD" lst[1
假设我有这些任务: points = [] point = (1, 2) 我怎么会这样做: points += point 它工作得很好,并且给了我点 = [1, 2]。但是,如果我这样做: poin
如何在 scala 中将 List[Task[List[Header]]] 类型转换为 Task[List[Header]]。 我有一个方法返回 Task[List[Header]] 并多次调用 do
如何在 Java 中查找二维列表的元素? 我有一个参数为 List> 的函数我想知道如何找到这个列表的行和列。 最佳答案 如果你喜欢 List> obj 然后你就可以像这样访问 obj.get(cur
分配 List到 List工作正常。 分配 List>到 List>不编译。 代码 public class Main { public static void main(String[] a
我正在用 Java 编写一个方法,该方法必须接收并迭代 Serializable 的 List。 有什么区别: public void myMethod(List list) { } 和 public
我看到很多人想用 mvvm 更新网格/列表/树的一部分,但他们不想刷新整个列表。 对于所有遇到此问题的人,我做了以下示例。 希望这对你有用。 最佳答案 这是一个简单的例子。整个代码中最重要的是: Bi
我正在为现有的 C++ 库编写包装器,该库使用列表,其中 T 是自定义结构。我被建议使用 vector 而不是列表,但我试图避免修改库。 为了更好地理解这个场景,我做了一个简单的应用程序,使用一个列表
List list List list 这两种声明有什么区别吗? 谢谢, 最佳答案 是的。 List可以包含所有派生自 Base 的不同事物的混合物. List包含同质项(从某种意义上说,它们必须全部
有人可以尽可能详细地解释以下类型之间的区别吗? List List List 让我更具体一点。我什么时候想使用 // 1 public void CanYouGiveMeAnAnswer(List l
我有一个元组列表,每个元组都是一对列表。所以我的数据看起来像: mylist = [(['foo', 'bar'], ['bar', 'bar']),(['bar', 'bar'],['bar', '
也许是一个时髦的标题,但我遇到了以下问题: 给定一个类型为 (a * b) list 的列表,我想创建一个类型为 (a * b list) list 的新列表。一个例子: 给定列表 let testL
我是一名优秀的程序员,十分优秀!