分页实践:前后端多种分页方式实现对比

在软件开发中,分页没有统一的规范,实现方式也各不相同,有的会返回总页数,有的会返回总条数,有的可以任意翻页。本文对比一下几种常见的分页方式。

总体来说,分页的实现方案分为四种:

  • 后端全部返回,由前端分页
  • limit offset方案
  • cursor方案
  • cursor方案与offset结合

后端全部返回,由前端分页#

sequenceDiagram
    participant 前端
    participant 后端
    前端 ->> 后端: 请求资源集数据
    后端 -->> 前端: 返回全部数据
前端功能 支持情况
显示总页 🙂
任意页码跳转 🙂
跳转附近数页 🙂
大量数据集 😭完全不可用
实现难度 简单

limit offset方案#

sequenceDiagram
    participant 前端
    participant 后端
    前端 ->> 后端: 请求满足条件的资源总数
    后端 -->> 前端: 返回满足条件的资源总数
    前端 ->> 后端: 请求资源集数据、PageNo
    后端 -->> 前端: 部分数据
前端功能 支持情况
显示总页 🙂
任意页码跳转 🙂
跳转附近数页 🙂
大量数据集 😭海量数据集下性能差
实现难度 相对简单

cursor方案#

sequenceDiagram
    participant 前端
    participant 后端
    前端 ->> 后端: 请求满足条件的资源总数
    后端 -->> 前端: 返回满足条件的资源总数
    前端 ->> 后端: 请求资源集数据、cursor、limit
    后端 -->> 前端: 部分数据、prevCursor、nextCursor
前端功能 支持情况
显示总页 🙂
任意页码跳转 😭
跳转附近数页 🙂
大量数据集 🙂
实现难度 相对复杂

如果每一次翻页都返回总页数的话,对性能来讲也是不小的开销。

相对动态的数据来说,如果不一直翻到没有数据为止,也不好确定是否到了最后一页。为了解决这个问题,以及跳转附近数页的问题,可以演进为这样的方案。

假定前端最多显示最近6页,每页50条数据,那么前端可以直接尝试预读300条数据,根据返回的数据来做局部的分页。一言以蔽之:读取更多的数据来进行局部分页。

cursor_preload

这里可以再简化一下前端的实现,添加offset参数,这样子前端只需要判断当前页前后数据条数是否足够,附近页的跳转可以通过携带offset字段请求得到。

cursor方案与offset结合#

cursor_offset