移动端列表查询最佳实践

不管是 pc 端仍是移动端,无可避免都会涉及到列表查询有关的操做,但对于这两种不一样的设备,其列表查询的最佳处理方式也是彻底不一样。前端

对于 pc 端列表查询来讲,前端一般是给与服务端当前须要获取的数据量(如 pageCount,limit 等参数)以及所须要获取数据的位置(如 pageSize,offset 等参数)做为查询条件。而后服务端而后返回数据总数,以及当前数据,前端再结合这些数据显示页面总数等信息。这里我称为相对位置取数。git

对于移动端而言,没有pc 端那么大的空间展现以及操做,因此基本上都会采用下拉取数这种方案。github

那么咱们在处理移动端列表查询时候使用这种相对位置取数会有什么问题呢?数据库

相对位置取数存在的问题

性能劣势

经过相对位置取数会具备性能问题,由于一旦使用 offset 信息来获取数据,随着页数的增长,响应速度也会变的愈来愈慢。由于在数据库层面,咱们每次所获取的数据都是“从头开始第几条”,每次咱们都须要从第一条开始计算,计算后舍弃前面的数据,只取最后多条数据返回前端。后端

固然了,对于相对位置取数来讲,数据库优化是必然的,这里我就很少作赘述了。对于前端开发来讲,优秀的的查询条件设计能够在必定方面解决此问题。api

数据显示重复

事实上,对于一个实际运行的项目而言,数据更新才是常态,若是数据更新的频率很高或者你在当前页停留的时间太久的话,会致使当前获取的数据出现必定的误差。服务器

例如:当你在获取最开始的 20 条数据后,正准备获取紧接着的后 20 条数据时,在这段时间内 ,发生了数据增长,此时移动端列表就可能会出现重复数据。虽然这个问题在 pc 端也存在,可是 pc 端只会展现当前页的信息,这样就避免了该问题所带来的负面影响。网络

结合列表 key 维持渲染正确

咱们在上面的问题中说明了,移动端下拉加载中使用相对位置查询取数是有问题的。性能

那么,若是当前不能迅速结合先后端进行修改 api 的状况下,当服务端传递过来的数据与用户想要得的数据不一致,咱们必须在前端进行处理,至少处理数据重复问题所带来的负面影响。优化

由于当前分页请求时无状态的。在分页取到数据以后前端能够对取得的数据进行过滤,过滤掉当前页面已经存在的 key(例如 id 等可以肯定的惟一键)。

经过这种处理方式,咱们至少能够保证当前用户看到的数据不会出现重复。同时当列表数据能够编辑修改的时候,也不会出现由于 key 值相同而致使数据错乱。

经过绝对位置获取数据

若是不使用相对位置获取数据,前端能够利用当前列表中的最后一条数据做为请求源参数。前端事先记录最后一条数据的信息。例如当前的排序条件为建立时间,那么记录最后一条数据的建立时间为主查询条件(若是列表对应的数据不属于我的,可能建立时间不能惟一决定当前数据位置,同时还须要添加 ID 等信息做为次要查询条件)。

当咱们使用绝对位置获取数据时候,虽然咱们没法提供相似于从第 1 页直接跳转 100 页的查询请求,但对于下拉加载这种类型的请求,咱们没必要担忧性能以及数据重复显示的问题。

对于相对位置取数来讲,前端能够根据返回数据的总数来判断。但当使用绝对位置取数时,即便获取数据总数,也没法判断当前查询是否存在后续数据。

从服务器端实现的角度来讲,当用户想要获得 20 条数据时候,服务端若是仅仅只向数据库请求 20 条数据,是没法得知是否有后续数据的。服务端能够尝试获取当前请求的数据条数 + 1, 如向数据库请求 21 条数据,若是成功得到 21 条数据,则说明至少存在着 1 条后续数据,这时候,咱们就能够返回 20 条数据以及具备后续数据的信息。但若是咱们请求 21 条数据却仅仅只能获取 20 条数据(及如下),则说明没有后续数据。

如能够经过 “hasMore” 字段来表示是否可以继续下拉加载的信息。

{
  data: [],
  hasMore: true
}

结合 HATEOAS 设计优化

事实上,前面咱们已经解决了移动端处理列表查询的问题。可是咱们作的还不够好,前端还须要结合排序条件来处理并提供请求参数,这个操做对于前端来讲也是一种负担。那么咱们就聊一下 HATEOAS 。

HATEOAS (Hypermedia As The Engine Of Application State, 超媒体即应用状态引发) 这个概念最先出如今 Roy Fielding 的论文中。REST 设计级别以下所示:

  • REST LEVEL 0: 使用 HTTP 做为传输方式
  • REST LEVEL 1: 引入资源的概念(每个资源都有对应的标识符和表达)
  • REST LEVEL 2: 引入 HTTP 动词(GET 获取资源/POST 建立资源/PUT 更新或者建立字样/DELETE 删除资源 等)
  • REST LEVEL 3: 引入 HATEOAS (在资源的表达中包含了连接信息。客户端能够根据连接来发现能够执行的动做)

HATEOAS 会在 API 返回的数据中添加下一步要执行的行为,要获取的数据等 URI 的连接信息。客户端只要获取这些信息以及行为连接,就能够根据这些信息进行接下来的操做。

对于当前的请求来讲,服务端能够直接返回下一页的信息,如

{
    data: [],
    hasMore: true,
    nextPageParams: {}    
}

服务端如此传递数据,前端就不须要对其进行多余的请求处理,若是当前没有修改以前的查询以及排序条件,则只须要直接返回 “nextPageParams” 做为下一页的查询条件便可。

这样作的好处不但符合 REST LEVEL 3,同时也减轻了前端的心智模型。前端无需配置下一页请求参数。只须要在最开始查询的时候提供查询条件便可。

固然,若是前端已经实现了全部排序添加以及查询条件由服务端提供,前端仅仅提供组件,那么该方案更能体现优点。 前端是不须要知道当前业务究竟须要什么查询条件,天然也不须要根据查询条件来组织下一页的条件。同时,该方案的输入和输出都由后端提供,当涉及到业务替换( 查询条件,排序条件修改)时候,前端无需任何修改即可以直接替换和使用。

其余注意事项

一旦涉及到移动端请求,不可避免的会有网络问题,当用户在火车或者偏远地区时候,一旦下拉就会涉及取数,可是当前数据没有返回以前,用户屡次下拉可能会有屡次取数请求,虽然前端能够结合 key 使得渲染不出错,可是仍是会在缓慢的网络下请求屡次,无疑雪上加霜。这时候咱们须要增长条件变量 loading。

伪代码以下所示:

// 查询
function search(cond) {
  loading = true  
  api.then(res => {
      loading = false
  }).catch(err => {
      loading = false
  })
}

// 获取下一页数据
function queryNextPage() {
    if (!nextPageParams) return
    if (!loading) return
    search(nextPageParams)
}

鼓励一下

若是你以为这篇文章不错,但愿能够给与我一些鼓励,在个人 github 博客下帮忙 star 一下。

博客地址

相关文章
相关标签/搜索