论坛分页频繁更新帖子缓存_如何实现频繁更改内容的“可缓存”分页

论坛分页频繁更新帖子缓存

by Nikita Kozlov

由Nikita Kozlov

如何实现频繁更改内容的“可缓存”分页 (How to implement “cacheable” pagination of frequently changing content)

Whenever we need to display a lot of content that is stored on the backend, we split it in chunks and then load them subsequently one piece at a time. This is a common approach, and there are multiple reasons why it is so great:

每当我们需要显示大量存储在后端的内容时,我们都会将其拆分为多个块,然后一次加载一次。 这是一种常见的方法,它之所以如此出色,有多种原因:

  1. It improves user experience. Loading a small single page takes less time, so the user can start consuming content faster.

    它改善了用户体验 。 加载单个小页面所需的时间更少,因此用户可以更快地开始使用内容。

  2. It reduces load on the network. A single page is small and light in terms of bandwidth. Plus, we can optimize battery and network consumption for mobile devices by adjusting the size of a single page.

    它减少了网络负载 。 一页很小,带宽很轻。 另外,我们可以通过调整单个页面的大小来优化移动设备的电池和网络消耗。

  3. It reduces load on the back end. Processing smaller pieces is faster then bigger ones. Users usually don’t need all the content at once, so average load-per-user is lower.

    它减少了后端的负载 。 处理较小的零件要快于较大的零件。 用户通常不需要一次获取所有内容,因此平均每用户负载较低。

Everybody wins. In most of the cases. But not all of them. As it often happens with generic solutions, the more domain-specific it gets, the better the solution that can be found. In this article, I want to share an interesting solution for one such case.

每个人都赢。 在大多数情况下。 但不是所有人。 通用解决方案经常发生这种情况,它获取的领域越多,找到的解决方案就越好。 在本文中,我想分享一种有趣的解决方案。

定义任务 (Defining the task)

Let’s imagine a collection that changes frequently over time. For example, we could look at a list of articles a user clapped for on Medium, or a wish list in a shopping application, or a history of any other users’ actions in general. Users can “add” as many items to that collection as they want.

让我们想象一个随时间变化的集合。 例如,我们可以查看用户在“媒体”上拍过的文章列表,或购物应用程序中的愿望列表,或一般而言其他任何用户的行为的历史记录。 用户可以根据需要向该集合“添加”任意数量的项目。

Our task is to display this collection in a convenient way, while doing our best to avoid abusing the network and therefore abusing battery and bandwidth.

我们的任务是以方便的方式显示此集合,同时尽最大努力避免滥用网络,从而避免浪费电池和带宽。

分页问题 (Problems with pagination)

One of the ways to minimize network usage is to cache responses. Most mobile and web applications heavily rely on the HTTP cache. It saves responses for a period of time specified in the response’s header. Every time an application makes a request, the HTTP client tries to get a corresponding response from the cache. Only if it is not available does it make an actual call to the backend.

最小化网络使用率的方法之一是缓存响应。 大多数移动和Web应用程序严重依赖HTTP缓存。 它将响应保存在响应头中指定的时间段内。 每次应用程序发出请求时,HTTP客户端都会尝试从缓存中获取相应的响应。 仅当它不可用时,它才会实际调用后端。

Sometimes this kind of caching does not work well for paginated content. If the collection is changed frequently and the content needs to be up-to-date, then it simply doesn’t make sense to cache the response at all. As an example, let’s imagine the following scenario:

有时,这种缓存不适用于分页内容。 如果集合频繁改变和内容的需求将上升,最新的,那么它根本没有任何意义缓存在所有的响应。 作为示例,让我们想象以下情形:

  1. The user opens the list of articles they clapped for here, on Medium. The first page is fetched from the backend.

    用户在“中”打开他们为此拍手的文章列表。 第一页是从后端获取的。
  2. After that, the user searched for something new, found another interesting article, and decided to recommend it.

    此后,用户搜索了一些新内容,找到了另一篇有趣的文章,并决定推荐它。
  3. Now they want to check the list of articles they recommended again.

    现在他们想再次查看他们推荐的文章列表。

The application needs to perform the very same request for the first page, but the result is different. The response can’t be cached.

该应用程序需要对首页执行完全相同的请求,但结果不同。 无法缓存响应。

If your domain-specific task allows you to rearrange items in this collection, then your problem is even worse. Because of the very same reason: the response is changing constantly.

如果您特定于域的任务允许您重新排列此集合中的项目,那么您的问题就更糟了。 由于同样的原因:响应在不断变化。

另一种方法 (Another approach)

Let’s take a closer look at the first page of data fetched from the backend. The response itself is a list of items in a particular order. Each item is unlikely to change. What changes is the order of elements and what items are on this list.

让我们仔细看看从后端获取的数据的第一页。 响应本身是特定顺序的项目列表。 每个项目都不太可能更改。 改变的是要素和项目是这个名单上有什么 顺序

This means that if we can fetch separately the order of the item IDs and the item details, then the second call can potentially be cached. As a matter of fact, even caching the second call is not straightforward — but we’ll get to it. For now, let’s make a separate request for each item:

这意味着,如果我们可以分别获取项目ID的顺序和项目详细信息,则可能会缓存第二个调用。 事实上,即使缓存第二个调用也不是一件容易的事,但是我们会继续讲下去。 现在,让我们对每个项目分别提出一个请求:

As you can see on the diagram above, because items are unlikely to change, we can cache item detail calls. Unfortunately, such a split will multiply the amount of network calls by an order of magnitude. But there is something we can do about it.

如上图所示,由于项目不太可能更改,因此我们可以缓存项目详细信息调用。 不幸的是,这样的划分会使网络呼叫的数量增加一个数量级。 但是我们可以做些什么。

我们到底想要什么? (What do we actually want?)

If we just request a bunch of items, we will encounter the same problem as the generic pagination approach. The HTTP cache won’t act as we want, so let’s write our own using similar but more deliberate logic.

如果我们只请求一堆物品,我们将遇到与通用分页方法相同的问题。 HTTP缓存不会发挥我们想要的作用,因此让我们使用类似但更深思熟虑的逻辑来编写自己的缓存。

This cache is not going to store batches, but single items for a particular amount of time. We will take the response, access its HTTP headers, and retrieve information about caching time. Then, we will put each item individually into the cache. Next time we need to display items, we can easily access cached ones and request the rest. In code it looks easier than it sounds:

此缓存将不存储批处理,而是存储特定时间段内的单个项目。 我们将获取响应,访问其HTTP标头,并获取有关缓存时间的信息。 然后,我们将每个项目分别放入缓存中。 下次我们需要显示项目时,我们可以轻松访问缓存的项目并请求其余项目。 在代码中看起来比听起来容易:

Let’s go quickly through the code. Method getOrderedItemsIds() returns the order of elements and is paginated. The most important part is method getItemsByIds(). This is a place where we first check what items are in the cache, and then request the rest from the backend. Please note that for the sake of simplicity, the code above is synchronous and probably won’t compile.

让我们快速浏览一下代码。 方法getOrderedItemsIds()返回元素的顺序并分页。 最重要的部分是方法getItemsByIds()。 在这里,我们首先检查缓存中有哪些项目,然后再从后端请求其余项目。 请注意,为简单起见,以上代码是同步的,可能不会编译。

After implementing this approach, the addition of a new item to the head of the list will cause a request for the order one of the item IDs and details for the new item. The rest comes from the cache.

实施此方法后,将新商品添加到列表的开头将导致要求订购商品ID和新商品详细信息之一。 其余的来自缓存。

A similar pair of calls will happen for each consecutive page. The main idea is that we can retrieve most item details from the cache. But unfortunately we have to request the order of item IDs for every page.

每个连续的页面都会发生类似的一对呼叫。 主要思想是我们可以从缓存中检索大多数项目详细信息。 但不幸的是,我们必须为每个页面请求商品ID的顺序。

做的更好 (Do it better)

The item IDs is usually a small object like a String or Universally Unique Identifier (UUID). Therefore, we can send bigger pages. Increasing the amount of item IDs returned by an order call decreases the number of calls, without abusing network bandwidth.

商品ID通常是一个很小的对象,例如字符串通用唯一标识符(UUID)。 因此,我们可以发送更大的页面。 订单呼叫返回的商品ID数量增加,从而减少了呼叫数量,而不会滥用网络带宽。

For example, instead of requesting 20–40 item IDs we can request 100-200. Later, the UI layer can moderate the number of item details that need to be displayed and request them accordingly. Then a sequence of calls will look something like this:

例如,我们可以请求100-200,而不是请求20-40个项目ID。 稍后,UI层可以调整需要显示的项目详细信息的数量,并相应地请求它们。 然后,一系列调用将如下所示:

  1. Request first 100 item IDs and keep them in memory.

    请求前100个项目ID,并将其保留在内存中。
  2. Request details for first 20 items (cache them of course) and display them to the user.

    请求前20个项目的详细信息(当然要缓存它们)并显示给用户。
  3. After the user scrolls through the first 20 items, request the second batch of 20 item details.

    用户滚动浏览前20个项目后,请请求第二批20个项目的详细信息。
  4. Repeat the previous step three more times and do similar steps for the next page of item IDs.

    再重复上一步三遍,并对下一页的项目ID执行类似的步骤。

Now adding a new item to the top still results in two requests (one for IDs and the other one for details of this new item). But we won’t have to request the next page for a while, because the pages are bigger. We also won’t need to request item details because they are cached!

现在,将新项目添加到顶部仍然会导致两个请求(一个请求ID,另一个请求有关此新项目的详细信息)。 但是我们不必再花一段时间请求下一页,因为页面更大。 我们也不需要请求商品详细信息,因为它们已被缓存!

Small disclaimer: the way UI moderates the requesting of item details can be more interesting. For example, it can skip requests for some items if the user scrolls too fast, because they’re not interested in them. But this deserves a whole other article.

小免责声明:UI缓和项目详细信息请求的方式可能更有趣。 例如,如果用户滚动太快,它可能会跳过对某些项目的请求,因为他们对此不感兴趣。 但这值得一整篇其他文章。

结论 (Conclusion)

General solutions are usually not optimized for particular cases. Knowing specifics can help us write faster, more optimized applications. For this case, the knowledge was crucial that content changes frequently and that it is a collection of items with IDs. Let’s review all the improvements the new approach brought:

一般解决方案通常不会针对特定情况进行优化。 了解细节可以帮助我们编写更快,更优化的应用程序。 对于这种情况,至关重要的是,知识必须经常更改,并且内容是具有ID的项的集合。 让我们回顾一下新方法带来的所有改进:

  1. Requesting the order of items separately enables us to cache details, even though we had to write a modified HTTP cache.

    单独请求项的顺序使我们能够缓存详细信息,即使我们必须编写修改后的HTTP缓存也是如此。
  2. Caching item details results in reduced usage of bandwidth.

    缓存项目详细信息会减少带宽的使用。
  3. Increased size of pages for the order request reduces the number of calls.

    订单请求页面的增加尺寸减少了呼叫数量。

One last thing: optimizations are awesome, and I found it exciting to write efficient code — but don’t forget to profile it first. Premature optimization could cause problems and we all should avoid it.

最后一件事:优化很棒,我发现编写高效的代码令人兴奋,但不要忘记先对其进行概要分析。 过早的优化可能会引起问题,我们都应避免这种情况。

Nikita Kozlov (@Nikita_E_Kozlov) | TwitterThe latest Tweets from Nikita Kozlov (@Nikita_E_Kozlov): “https://t.co/wmGSJ7snW1"twitter.com

Nikita Kozlov(@Nikita_E_Kozlov)| Twitter 来自Nikita Kozlov(@Nikita_E_Kozlov)的最新推文:“ https://t.co/wmGSJ7snW1” twitter.com

Thank you for you time reading this article. If you like it, don’t forget to click the ? below.

感谢您抽出宝贵的时间阅读本文。 如果喜欢,不要忘记单击“ ?”。 b低

翻译自: https://www.freecodecamp.org/news/how-to-implement-cacheable-pagination-of-frequently-changing-content-c8ddc8269e81/

论坛分页频繁更新帖子缓存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值