记一次Promise在api接口合并中的实践

写在前面的话

  1. 本篇水文发出来之后,有朋友反馈文笔太差,的确是作者的锅,码字水平目前就这么高,只能委屈大家看这篇辣眼睛的文字了,文笔只能慢慢改善。
  2. 还有朋友反馈看懵的,仔细想想也是作者的锅,没有表达清楚,修改重发。
  3. 澄清一下本文和Promise.all没有半毛钱关系,如果让大家误会,见谅。
  4. 有朋友希望快速浏览能有一句总结,不想看代码。这里解释一下,其实总结就包含在下文合并接口的解释里,本文要解决的业务相对比较小众,脱离场景谈总结也没啥意义,不看业务场景和代码,本文真的没有任何的价值,主要是记录开发业务的一个思路。

关于接口合并(不知道有没有专门的术语,暂且如此称呼)在这里解释一下,本文所指的是页面初始化加载数据是一个api接口,而加载更多数据的是另一个api接口,前一个接口肯定会调用,第二个接口不一定会被调用(用户触发),但是我们把两个调用接口封装起来,公用一个业务逻辑,作者比较懒不想给两个接口分别写业务逻辑。

一. 前言

上次作者在个人项目中遇到的post预检请求bug,水了一篇小文《记一次跨域post请求数据之preflight request》,本文也只是记录在特定项目中如何抽取业务逻辑,封装两个api接口公用一段业务逻辑的思路,对读者朋友们有所启发,那就最好不过了,有什么问题或者错漏之处欢迎大家提出来分享,作者此文权当抛砖引玉。

关于接口合并,作者在项目开发文档中也有描述,有兴趣的可以去瞅瞅。

二. 猫眼API接口分析

脱离业务谈编码就是耍流氓。下面简单介绍一下猫眼的接口,其中我们发现在猫眼的两个页面中可以使用接口合并,现在以猫眼正在热映页面的两个api为例。

1 初始化获取当前热映电影列表

以下都将以 api_1 指称 初始化获取当前热映电影列表api接口

1.1说明
信息说明
功能初始化获取电影信息
URL//m.maoyan.com/ajax/movieOnInfoList
格式JSON
HTTP METHODGET
1.2 请求参数
参数类型必选说明
tokenStringfalse登录之后的凭证
1.3返回字段
字段类型说明
movieListArray电影列表(默认一次返回10条)
totalNumber电影总数目, total >= movieList.length
movieIdsArray所有电影ID,总数同total,后续请求更多电影时必须依赖它们
comingArray更多电影列表,第一次请求必定是空
1.4 接口示例

//m.maoyan.com/ajax/movieOnInfoList?token

{
  "coming": [],
  "stid": "576591972453269000",
  "movieIds": [247295, 410629, 1206605, 248906, 341139, 1250341, 1218091, 344869, 1243239, 580298, 907653],
  "movieList": [
    "同下方获取当前热映更多电影列表接口返回的coming字段"
  ],
  "stids": [
    {"movieId": 247295, "stid": "576591972453269000_a247295_c0"}
  ],
  "total": 11
}
复制代码

2 获取当前热映更多电影列表

以下都将以 api_2指称 获取当前热映更多电影列表api接口

2.1 说明
信息说明
功能获取hot更多电影列表
URL//m.maoyan.com/ajax/moreComingList
格式JSON
HTTP METHODGET
2.2 请求参数
参数类型必选说明列子
tokenStringfalse登录之后的凭证
movieIdsStringtrue请求的电影ID,依赖初始化接口的接口返回字段movieIds"1214652,1229799,1251606"
2.3 返回字段
字段类型说明
comingArray更多电影列表
2.4 接口示例

//m.maoyan.com/ajax/moreComingList?token=&movieIds=1214652%2C1229799%2C1251606%2C1215114

{
  "coming": [
    {
      "id": 1214652,
      "comingTitle": "2月22日 周五",
      "globalReleased": true,
      "haspromotionTag": false,
      "img": "http://p0.meituan.net/w.h/movie/979266668d0e94dc83956a70d22b4eaa184105.jpg",
      "nm": "朝花夕誓-于离别之朝束起约定之花",
      "preShow": false,
      "rt": "2019-02-22",
      "sc": "9.2",
      "showInfo": "今天10家影院放映21场",
      "showst": "3",
      "star": "石见舞菜香,入野自由,茅野爱衣",
      "version": "",
      "wish": 76220,
      "wishst": 0,
    },
    ...略
  ]
}
复制代码

上面两大坨数据,就是作者整理的api接口文档,仔细观察两个api接口的返回字段,都有一个coming字段,作者最初的灵感也是来自于它们,api_1接口的数据列表放在movieList字段中,我们下面就将以Promise来处理coming和movieList。

有朋友关注api_2接口依赖于api_1接口,猫眼的api就是这么设计的,api_1接口返回了部分电影列表、全部的电影id和电影总数,api_2接口请求只需传递电影id就可以了。其他公司设计的api接口请求参数可能就是offset和limit。

三. 方案

要进行接口合并,无非要解决两个问题, 判断接口、处理数据

1 判断接口

api_2接口请求数据的时候必定需要知道请求的是那些电影的ID,那么我们肯定要在本地定义一个offset作为数据的偏移量,作者的项目是vue写的,就放在了vue的组件实例上了。我们将offset设为0,第一次请求时offset必定为0,我们就将offset的值作为判断接口的依据。

下面直接上代码

/***
*  业务逻辑部分
*  1. isFirst判断是否第一次请求
*  2. getInfoListAction(isFirst) 得到最终的api操作函数 getMovieInfoList
*  关于 getInfoListAction请参看下文 @src src\api\index.js
***/
import { getInfoListAction } from '@/api'

const { offset, limit, total } = this
const isFirst = offset === 0
const getMovieInfoList = getInfoListAction(isFirst)
getMovieInfoList(params).then(data => {
    // ....数据处理此处略,详见下文
})
复制代码

难道直接用if-esle来硬编码判断?作者当然不会这么糊弄大家了。

/** 
*  @addr src/api/index.js
*  @ getMovieOnInfoList 初始api的操作函数
*  @ getMoreComingList 加载更多数据的操作函数
*  @ getInfoListAction通过上文的isFirst作为参数调用来判断返回 getMovieOnInfoList还是 getMoreComingList(也就是上文提到的getMovieInfoList)
 *  关于 getDataByAction 参看下文 @addr src/util/index.js
**/
import request from '@/util/request'
import { getDataByAction } from '@/util'

const getMovieOnInfoList = request('/movieOnInfoList')
const getMoreComingList = request('/moreComingList')
export const getInfoListAction = getDataByAction(getMovieOnInfoList, getMoreComingList)

/*** 
*  @addr src/util/index.js
*  @getDataByAction 使用函数柯里化,接受两个操作函数返回一个新函数,在业务逻辑中返回最终的api操作函数
**/
export const getDataByAction = (initAction, nextAction) => (isFirst) => isFirst ? initAction : nextAction

// @addr src/util/request.js
import Axios from 'axios'
let baseURL = process.env.VUE_APP_URL

const defaultConfig = {
  baseURL
}

const STATUS_CODE = 200

const instance = Axios.create(defaultConfig)

const request = (url, method = 'get') => (params) => {
  return instance({
    url,
    method,
    ...params
  }).then(resp => {
    if (resp.status === STATUS_CODE) {
      return resp.data
    }
  })
}
export default request
复制代码

请忽略作者的request函数的丑陋封装,没有做错误处理,(逃

2 数据处理

由上文可知,我们最终的api调用函数调用之后其实是返回了一个Promise{<resolve>:data}

我们在vue组件实例上定义了movieList存放数据,movieIds存放第一次返回时movieIds字段的数据,total数据总数。

// 接上文的省略的代码部分
// 暂时忽略params参数,下文有处理详解

/**
*  1. 在promise.then的函数中,我们从data数据里取 movieIds, movieList, coming, total字段
*  2.1 我们以movieIds判断是第一次调用api接口(其他字段也可以,这里先偷懒),那么我们赋值需要的数据 movieIds,total,直接返回movieList数据.
*  2.2 如果2.1没有执行,那么肯定是加载更多数据的接口api_2,我们直接返回coming字段
*  3. 从2.1、2.2我们获得了最后的数据Array,判断数据的长度,更新offset偏移量和movieList数据
*  ps: setImgSize是处理图片的函数,不必理会
**/
getMovieInfoList(params).then(data => {
  const { movieIds, movieList, coming, total } = data
  if (movieIds) {
    this.movieIds = movieIds
    this.total = total
    return movieList
  }
  return coming
}).then(data => {
  if (data.length) {
    this.offset += data.length
    this.movieList.push(...setImgSize(data))
    $state.loaded()
  } else {
    $state.complete()
  }
})
复制代码

3 参数处理

const { offset, limit, total } = this
const isFirst = offset === 0
if (offset && offset > total) return
const movieIds = this.movieIds
  .slice(offset, offset + limit)
  .join()
const params = { params: { ...this.params, movieIds } }
复制代码

结尾

水到现在终于要结束了,挤一挤好像也没啥干货,关于接口合并,智者见智,万一以后改接口爆炸了也说不定,作者只是记录下当前遇到类似情况的一种处理方案,或者有更好的方案欢迎大家分享,行文错漏、改善之处欢迎提出来探讨。

Tips: 每天水一篇,生活乐无边。

转载于:https://juejin.im/post/5c80b548518825407b2b64a4

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值