前言
在需要展示大量的列表式数据时,我们都以分页加载的方式来展示,这也是行业内惯用的方法,这种方式加速了首页内容的展示、节约了流量资源及CPU处理资源,也优化了用户体验。
方案1
既然是分页加载,那么在请求时首先要提交页码信息,所以请求接口可能是这样的:
GET http://example.com/api/address?page_index=3&page_size=20&sort=date
返回的数据可能就是下面这样:
{
"error_code": 1000,
"error_msg": "成功",
"extra": {
"data": [
{...},
{...},
{...},
]
},
"next_page": 3
}
方案2
在方案1的基础上,加上优化,传入的不是页码,而是条目的索引位置:
GET http://example.com/api/address?item_index=7&page_size=20&sort=date
返回的数据如下:
{
"error_code": 1000,
"error_msg": "成功",
"extra": {
"data": [
{...},
{...},
{...},
]
},
"next_index": 73
}
方案2只是在方案1的基础上做了优化,增加了自由度而已。
问题
上面列举的方案1和方案2,在面对相对静态的数据时,是没有问题的,但是,当云端数据是动态可变时(特别当条目可以被删除时),会出现数据遗漏的问题,拿方案1举例分析:
- 假设云端数据是1、2、3、... 这样顺序排列的,我们先拉取第一页:
GET http://example.com/api/address?page_index=0&page_size=20
- 则我们得到1、2、3、...、20,这20条数据
- 在数据展示页面,我们删除第一条数据,然后拉取第二页
GET http://example.com/api/address?page_index=1&page_size=20
- 因为云端数据现在是2、3、4、...,所以第二页数据从22开始的,所以我们得到22、23、24、...、41
发现了什么没有?条目21被漏掉了,这是很明显的错误。
方案3
不使用页数和条目索引这两种方式,而是使用条目id来避开问题:
GET http://example.com/api/address?start_id=7&page_size=20
返回数据:
{
"error_code": 1000,
"error_msg": "成功",
"extra": {
"data": [
{...},
{...},
{...},
]
},
"next_id": 73
}
回头看上面那个例子,第一次调用返回next_id为21,在这个页面删除多条数据后,下一页请求是:
GET http://example.com/api/address?start_id=21&page_size=20
依然返回id为21那个条目开始的20条数据,避开了上面那个问题。
总结
方案1只能用于数据相对静态的场景,比如高德地图的搜索接口,就是用offset+size的方式来分页加载,因为查询结果是固定的,如果数据是动态的,分页加载过程中存在被删除的可能,则不能使用方案1和方案2,方案3是首选,微博、twitter、Facebook这种社交平台的开放api用的就是这种,只是更复杂,用到了since_id、since_date、max_id、max_date等条件,感兴趣的可以去看看。
实际项目中我的所有的分页加载都使用方案3,请求参数有start_id,返回参数有next_id,start_id 不传或者传-1时,返回第一页数据以及下一页第一条数据的id,也就是next_id,这个值在请求下一页时直接提交给start_id便可。