草庐IT

列表分页接口有哪些方案,你知道吗?

彭旭锐 2023-03-28 原文

你的支持对我意义重大!

? Hi,我是小彭。本文已收录到 GitHub · Android-NoteBook 中。这里有 Android 进阶成长路线笔记 & 博客,有志同道合的朋友,欢迎跟着我一起成长。(联系方式在 GitHub)

前言

  • 列表是 App 中很常见的一种内容排列形式,常见的列表样式有卡片流、瀑布流、信息流等,那么这些列表有什么区别呢?在这篇文章里,我将总结常见的列表样式以及接口分页设计相关问题。如果能帮上忙,请务必点赞加关注,这真的对我非常重要。

1. 常见列表样式

1.1 传统 PC 列表

我们先说一种我们很熟悉的 PC 列表样式,列表底部会带有 上一页/ 下一页 / 页码 的页码切换功能,比如淘宝、百度、京东等列表。这类样式最大的特点是浏览的节奏感,在用户浏览一页数据后会有停顿,因此列表底部常常会设置相关推荐、猜你喜欢等功能。

传统 PC 列表对屏幕尺寸有一定要求,因此在手机端很少见。那么手机端有哪些常见的列表样式呢?从数据是否有尽头,可以分为普通列表和瀑布流列表。

1.2 普通列表

普通列表是相对于瀑布流列表的,普通列表的内容是有限的,只要一直滑总能滑到尽头。从单个数据项的设计样式区分,可以分为纯文字、图文混排、卡片三种:

  • 纯文字: 以文字信息为主导的布局形式,例如手机短信列表;
  • 图文混排: 以文字 + 图文的信息布局形式,能够快速突出重点。除了标准的单列布局方式外,多种布局形式混合使用能够让布局内容更加多化;
  • 卡片: 将卡片颜色与列表背景颜色可以区分,使得视觉上能够轻易感知到卡片矩形的存在。同时,借助了卡片后景深(也就是卡片阴影)将页面 XY 轴扩展到 XYZ 三轴,从而加强了视觉层级丰富性。目前,卡片式设计已经成为 App 中使用非常广告的设计样式。除了标准的单列布局外,双列卡片流也很常见。

1.3 瀑布流列表

相对于简单列表,瀑布流列表指内容像瀑布一样源源不断,一直滑不到尽头的列表。最常见的一种瀑布流是信息流(或 Feed 流),几乎每个产品都存在信息流。信息流在分发内容时,会根据用户的喜好对内容进行干预,更精准地向用户推荐内容。我们熟悉的产品中有哪些是信息流呢?

  • 微信朋友圈:不算信息流,朋友圈是按照最近发布时间排序,且存在尽头;
  • 知乎回答列表:不算信息流,回答列表是按照热度等指标综合排序,且存在尽头;
  • 抖音首页 / 小红书首页:算信息流,根据用户推荐,且滑不到尽头。

即使列表的数据量很小,列表接口也应该在一开始就支持分页增量请求,避免将来再支持时的兼容问题。那么,列表分页有哪些设计方案呢?


2. 基于偏移分页

基于偏移是最常见的分页接口设计,其原理是通过数据库查询语句的 offset + limit 指定某一分页的数据。例如:

# 获取第 curPage 页数据,每页数据量为 pageSize
select * from ... where ... order by ... limit (curPage - 1) * pageSize, pageSize

因此,前端参数需要指定请求的页码 page 和可选的每页数据量 size:

第一页请求:
page : 1  // 当前页码,必选
size : 10 // 每页数据量,可选

响应:
list:[{1},{2},{3}...,{10}]   // 列表数据
total:100                    // 数据总量

-----------------------------------

第二页请求:
page : 2  // 当前页码,必选
size : 10 // 每页数据量,可选

响应:
list:[{11},{12},{13}...,{20}]   // 列表数据
total:100                       // 数据总量

基于偏移的分页方案优势在于简单易理解,而且能够支持点击 上一页/ 下一页 / 页码 按钮切换分页,实现传统 PC 列表的样式。但劣势也是很明显的,主要分为两个方面:

  • 慢查询: SQL 查询语句在配合 offset、limit 查询时,如果 offset 偏移过大,会造成慢查询;
  • 动态数据: 从前端展示一页数据到增量请求下一页数据之间会有一个时间差,如果这段时间内数据存在更新,则在请求下一页数据时可能会存在重复或缺失。我画了个示意图帮助你理解为什么数据更新会引起重复或缺失:

数据重复的情况虽然可以通过前端去重的方式避免,但也会导致新一页展现的数据量参差不齐。那么,对于动态数据的场景,应该如何设计分页接口呢?


3. 基于游标分页

基于游标的分页设计适用于动态数据场景,其原理是根据已获取的最后一条数据的 ID 作为参数来请求下一页数据。例如:

# 获取第 curCursor 后的一页数据,每页数据量为 pageSize
select * from ... where ... and id > $curCursor order by id limit ($curPage - 1) * $pageSize, $pageSize

因此,前端在请求分页接口时,不再指定下一个页码 page,而是根据已接收的最后一条数据的 ID 来请求下一页数据:

第一页请求:
cursor : 0  // 当前游标,必选
size : 10   // 每页数据量,可选

响应:
list:[{1},{2},{3}...,{10}]   // 列表数据
total:100                    // 数据总量

-----------------------------------

第二页请求:
cursor : 10  // 当前游标,必选
size : 10   // 每页数据量,可选

响应:
list:[{11},{12},{13}...,{20}]   // 列表数据
total:100                       // 数据总量

为什么游标的方案可以避免数据重复或缺失呢?这是因为无论数据发生新增还是减少时,基于游标的分页请求都获取该游标后续的一页数据,而基于偏移的分页请求是获取变更后数据排序后指定偏移位置的数据,这些数据在之前的请求中是否重复或缺失是无从得知的。

当然了,基于游标的分页方案也存在局限性:

  • 不可以支持点击 上一页/ 下一页 / 页码 按钮切换分页,App 基本不存在传统 PC 列表的操作,几乎没有影响;
  • 只适合简单排序场景,例如按照时间排序或主键 ID 排序(主键 ID 通常是按照插入时间递增的)

参考资料:

你的点赞对我意义重大!希望大家可以一起讨论技术,找到志同道合的朋友,我们下次见!

有关列表分页接口有哪些方案,你知道吗?的更多相关文章

  1. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  2. ruby - RVM 使用列表[0] - 2

    是否有类似“RVMuse1”或“RVMuselist[0]”之类的内容而不是键入整个版本号。在任何时候,我们都会看到一个可能包含5个或更多ruby的列表,我们可以轻松地键入一个数字而不是X.X.X。这也有助于rvmgemset。 最佳答案 这在RVM2.0中是可能的=>https://docs.google.com/document/d/1xW9GeEpLOWPcddDg_hOPvK4oeLxJmU3Q5FiCNT7nTAc/edit?usp=sharing-知道链接的任何人都可以发表评论

  3. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  4. ruby-on-rails - 您希望看到哪些 Rails 插件? - 2

    您认为可以作为插件很好地存在于您的Rails应用程序中必须实现的哪些行为?您过去曾搜索过哪些插件功能但找不到?哪些现有的Rails插件可以改进或扩展,如何改进或扩展? 最佳答案 我希望在管理界面中看到一个引擎插件,它提供了应用程序中所有模型的仪表板摘要,以及可配置的事件图表。 关于ruby-on-rails-您希望看到哪些Rails插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questio

  5. ruby - EventMachine - 你怎么知道你是否落后了? - 2

    我正在研究使用EventMachine支持的twitter-streamruby​​gem来跟踪和捕获推文。我对整个事件编程有点陌生。我如何判断我在事件循环中所做的任何处理是否导致我落后?有没有简单的检查方法? 最佳答案 您可以通过使用周期性计时器并打印出耗时来确定延迟。如果您使用的是1秒的计时器,您应该已经过了大约1秒,如果它更长,您就知道您正在减慢react器的速度。@last=Time.now.to_fEM.add_periodic_timer(1)doputs"LATENCY:#{Time.now.to_f-@last}"@

  6. Ruby on Rails regexp equals-tilde 与 array include 用于检查选项列表 - 2

    我正在使用Rails3.2.3和Ruby1.9.3p0。我发现我经常需要确定某个字符串是否出现在选项列表中。看来我可以使用Ruby数组.includemethod:或正则表达式equals-tildematchshorthand用竖线分隔选项:就性能而言,一个比另一个好吗?还有更好的方法吗? 最佳答案 总结:Array#include?包含String元素,在接受和拒绝输入时均胜出,对于您的示例只有三个可接受的值。对于要检查的更大的集合,看起来Set#include?和String元素可能会获胜。如何测试我们应该根据经验对此进行测试

  7. Ruby 守护进程和 JRuby - 备选方案 - 2

    我有一个应用程序正在从Ruby迁移到JRuby(由于需要通过Java提供更好的Web服务安全支持)。我使用的gem之一是daemons创建后台作业。问题在于它使用fork+exec来创建后台进程,但这对JRuby来说是禁忌。那么-是否有用于创建后台作业的替代gem/wrapper?我目前的想法是只从shell脚本调用rake并让rake任务永远运行......提前致谢,克里斯。更新我们目前正在使用几个与Java线程相关的包装器,即https://github.com/jmettraux/rufus-scheduler和https://github.com/philostler/acts

  8. ruby - 每个页面上的 Jekyll 分页 - 2

    据我们所知,Jekyll默认分页仅支持index.html,我想创建blog.html并在那里包含分页。有什么解决办法吗? 最佳答案 如果您创建一个名为/blog的目录并在其中放置一个index.html文件,那么您可以向_config.yml表示paginate_path:"blog/page:num"。不是使用根文件夹中的默认index.html作为分页器模板,而是使用/blog/index.html。分页器将根据需要生成类似/blog/page2/和/blog/page3/的页面。这将使您到达yourwebsite.com/b

  9. ruby - 实现k最近邻需要哪些数据? - 2

    我目前有一个reddit克隆类型的网站。我正在尝试根据我的用户之前喜欢的帖子推荐帖子。看起来K最近邻或k均值是执行此操作的最佳方法。我似乎无法理解如何实际实现它。我看过一些数学公式(例如k表示维基百科页面),但它们对我来说并没有真正意义。有人可以推荐一些伪代码,或者可以查看的地方,以便我更好地了解如何执行此操作吗? 最佳答案 K最近邻(又名KNN)是一种分类算法。基本上,您采用包含N个项目的训练组并对它们进行分类。如何对它们进行分类完全取决于您的数据,以及您认为该数据的重要分类特征是什么。在您的示例中,这可能是帖子类别、谁发布了该项

  10. Ruby:如何将数组拼接成 Lisp 风格的列表? - 2

    这是我发现自己偶尔想做的事情。假设我有一个参数列表。在Lisp中,我可以像这样`(imaginary-function,@args)为了调用将数组从一个元素转换为正确数量的参数的函数。Ruby中是否有类似的功能?或者我只是在这里使用了一个完全错误的成语? 最佳答案 是的!它被称为splat运算符。a=[1,44]p(*a) 关于Ruby:如何将数组拼接成Lisp风格的列表?,我们在StackOverflow上找到一个类似的问题: https://stackov

随机推荐