如何使用反应流处理开放式分页? [英] How to handle open ended pagination using reactive streams?

查看:92
本文介绍了如何使用反应流处理开放式分页?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的redux应用程序中为所有异步请求处理使用 RxJS .我特别要用的一件事是枚举分页的AWS API的所有结果.这些API通常不允许随机跳页,必须从上一次调用中使用特殊令牌(nextToken)调用该API,并遵循该顺序.如果没有随响应发送nextToken,则该列表是完整的.

I am using RxJS for all async request handling in my redux application. One thing in particular I am using it for is enumerating all the results from a paginated AWS API. Those APIs generally do not allow random page jumping, one must call the API with a special token (nextToken) from the previous call and follow the sequence. The list is complete when there is no nextToken sent with the response.

我想做的是获取部分页面结果流,最后我可以将其展平为一个数组.预期的好处是,当用户在获取列表的应用程序中留下一个特定的屏幕时,我可以从流中取消订阅这些页面,并且不会获取其余页面(永远不会显示).

What I would like to do is have a stream of the partial page results that I can at the end flatten into one array. The expected benefit is that when the user leaves a particular screen in the app that fetched the list, I can unsubscribe them from the stream and the remaining pages (which will never get displayed) won't be fetched.

我正在努力地理解如何在不进入Rx.Subject的领域并将其手动推入令牌的情况下,相对纯粹"地创建这样的流.我担心如果我这样手动"执行操作,我将面临潜在的内存泄漏或由于无法取消订阅和其他编码错误而导致的其他错误.

I am struggling to understand how I can create such a stream relatively "purely" without going into the territory of Rx.Subject and pushing the tokens into it manually. I fear that if I do it "manually" like this, I will be exposed to potential memory leaks or other bugs resulting from failure to unsubscribe and other coding errors.

推荐答案

您可以使用expand运算符来实现分页.您可以使用可观察的通知程序来控制页面的检索. takeconcatMap运算符可用于确保在发出通知程序之前不会检索下一页.

You can use the expand operator to implement paging. And you can control the retrieval of the pages using a notifier observable. The take and concatMap operators can be used to ensure the next page isn't retrieved until the notifier emits.

通知者可以是任何合适的可观察者.例如,当用户滚动到列表底部时,可以使用Subject并在其上调用next.

The notifier can be whatever observable is suitable. For example, you could use a Subject and call next on it when the user scrolls to the bottom of the list.

此代码段使用GitHub API遍历加星标的软件仓库-使用Link标头指示next页面的URI.从概念上讲,这与AWS API的机制相同(但我可以在代码段中运行它).

This snippet pages through starred repos using the GitHub API - which uses the Link header to indicate the URI for the next page. Conceptually, this is the same mechanism as with the AWS API (but I can run it in a snippet).

评论应说明其工作原理.

The comments should explain how it works.

// The GitHub API uses the Link header for paging.
// Map the response to an object that contains the content and the
// URI for the next page (if there is one).

function get(uri) {
  return Rx.Observable.ajax
    .get(uri)
    .map(response => ({
      content: response.response,
      next: next(response)
    }));
}

function next(response) {
    const link = response.xhr.getResponseHeader("Link");
    if (link) {
        const match = link.match(/<([^>]+)>;\s*rel="next"/);
        if (match) {
            return match[1];
        }
    }
    return null;
}

// Use a notifier observable to control the paging.
// Here, the notifier is a timer, but it could be a subject that's
// triggered when the used scrolls to the bottom of the list, etc.

const notifier = Rx.Observable.defer(() => {
  console.log("waiting...");
  return Rx.Observable
    .timer(1000)
    .do(() => console.log("notifying..."));
});

// Use the expand operator to retrieve the next page, if there is
// one. The concatMap operator will ensure the next page isn't retrieved
// until the notifier next emits a value (which is ignored).
// The mergeMap operator will flatten the repos in the content array
// into the observable stream - so the observable emits repos and not
// arrays of repos.

const starred = get("https://api.github.com/users/voy/starred")
  .expand(({ next }) => next ?
    notifier.take(1).concatMap(() => get(next)) :
    Rx.Observable.empty()
  )
  .mergeMap(({ content }) => content);

starred.subscribe(
  repo => console.log(`  ${repo.name}`),
  undefined,
  () => console.log("finished paging")
);

.as-console-wrapper { max-height: 100% !important; top: 0; }

<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>

这篇关于如何使用反应流处理开放式分页?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆