一、为什么要有分页
在实战开发中,如果需要做Feed流且上拉加载更多内容,说明后端肯定有很多的数据,那么向后端获取数据的时候,总不能一次性加载所有的数据吧,这样会导致加载速度变慢,且后端数据库的压力很大。
那么我们在获取数据的时候,可以分次获取,每次获取一定数量的数据,用户上拉的时候再拉取下一页,再发起一次请求,这就是分页机制。
在Appwrite中常用的分页方式有两种:
- 基于页码 的
Offset分页 - 基于游标 的
Cursor分页。
二、Offset分页(页码式分页)
Offset分页 是基于页码的,原理是记录当前的页码page,获取数据的时候从数据集中跳过前面的offset = (page - 1) * limit 条,获取limit条数据。
优点:
- 逻辑直观好理解,实现简单
- 适合数据量不大、不常变动的场景
缺点:
- 数据频繁变动的时候(增加减少数据)可能会导致缺漏和重复,因为整体的数据会偏移
- 数据量大的时候,需要跳过大量的数据,后端在处理的时候效率会降低
使用示例:
javascript
import { Query } from "appwrite";
async function fetchPage_offset(page = 1, limit = 15) {
const offset = (page - 1) * limit;
const res = await databases.listDocuments(DB_ID, COLLECTION_ID, [
Query.orderDesc("$createdAt"), //排序
Query.limit(limit), //限制数据数量
Query.offset(offset), //偏移量
]);
return res; // 返回来的数据在res.documents, 数量是res.total
}
使用场景: 小型数据集、开发期快速验证、或者你需要精准的"页码跳转到第x页"体验。
三、Cursor分页
Cursor分页 是基于游标的,原理是每次请求都按照某个顺序取一定数量的数据(一般是按照创建时间),取完以后拿出最后一条数据的ID 作为游标,下一次请求的时候从这个游标之后继续取,这样定位准确,不会缺漏记录。
相当于看书,往看到的地方插个书签,下次再读就不会找错了。
优点
- 性能更高,数据库不需要跳过大量记录
- 稳定性强,在数据被频繁插入和删除时更可靠,以游标为基础,不易缺漏和重复
- 适合无限滚动的场景
缺点
- 需要按稳定字段排序 (通常是创建时间
$createdAt或其它有索引的字段) - 实现时要处理排序方向(asc/desc)和 cursor 的关系
- 无法直接跳转到某一页
使用示例
javascript
import { Query } from "appwrite";
//第一次请求
async function fetchFirstPage_cursor(limit = 15) {
const res = await databases.listDocuments(DB_ID, COLLECTION_ID, [
Query.orderDesc("$createdAt"), //排序
Query.limit(limit), //取limit条数据
]);
return res; // 数据在res.documents, 数量是res.total
}
// 获取到数据后,保存最后一条数据的ID作为游标
// const lastDocId = res.documents[res.documents.length - 1].$id;
//下一页请求
async function fetchNextPage_cursor(lastDocId, limit = 15) {
const res = await databases.listDocuments(DB_ID, COLLECTION_ID, [
Query.orderDesc("$createdAt"),
Query.cursorAfter(lastDocId), //从游标处后面找起
Query.limit(limit),
]);
return res;
}
注意 :cursorAfter/cursorBefore 这两个方法是基于游标,不是基于时间戳。所以在使用的时候需要和排序结合使用,先排序后按游标查找,效果更稳定。
四、总结
-
方法选择:
- Offset分页:数据量小,需要直接跳转到第x页的场景,实现简单
- Cursor分页:数据量大的大部分场景,例如Feed流、评论区、聊天记录或大型数据集,效果更好,但稍微复杂
-
分页大小(limit):为了保证首屏加载的效率,量不需要太大,可以在8~20之间
-
游标选择 :使用 Cursor 分页时,确保排序字段稳定且有索引(如
$id或$createdAt,但Appwrite官方文档中使用的是id)。 -
去重策略:不管使用什么方法分页,获取到新数据后,都要记得去重,以免出现重复的数据
-
刷新(pull-to-refresh)策略:下拉刷新通常应该重新拉第一页,并替换列表数据而不是追加