關於接口合併(不知道有沒有專門的術語,暫且如此稱呼)在這裏解釋一下,本文所指的是頁面初始化加載數據是一個api接口,而加載更多數據的是另外一個api接口,前一個接口確定會調用,第二個接口不必定會被調用(用戶觸發),可是咱們把兩個調用接口封裝起來,公用一個業務邏輯,做者比較懶不想給兩個接口分別寫業務邏輯。javascript
上次做者在我的項目中遇到的post預檢請求bug,水了一篇小文《記一次跨域post請求數據之preflight request》,本文也只是記錄在特定項目中如何抽取業務邏輯,封裝兩個api接口公用一段業務邏輯的思路,對讀者朋友們有所啓發,那就最好不過了,有什麼問題或者錯漏之處歡迎你們提出來分享,做者此文權當拋磚引玉。vue
關於接口合併,做者在項目開發文檔中也有描述,有興趣的能夠去瞅瞅。java
脫離業務談編碼就是耍流氓。下面簡單介紹一下貓眼的接口,其中咱們發如今貓眼的兩個頁面中可使用接口合併,如今以貓眼正在熱映頁面的兩個api爲例。ios
如下都將以 api_1 指稱 初始化獲取當前熱映電影列表api接口git
信息 | 說明 |
---|---|
功能 | 初始化獲取電影信息 |
URL | //m.maoyan.com/ajax/movieOnInfoList |
格式 | JSON |
HTTP METHOD | GET |
參數 | 類型 | 必選 | 說明 |
---|---|---|---|
token | String | false | 登陸以後的憑證 |
字段 | 類型 | 說明 |
---|---|---|
movieList | Array | 電影列表(默認一次返回10條) |
total | Number | 電影總數目, total >= movieList.length |
movieIds | Array | 全部電影ID,總數同total,後續請求更多電影時必須依賴它們 |
coming | Array | 更多電影列表,第一次請求一定是空 |
//m.maoyan.com/ajax/movieOnInfoList?tokengithub
{
"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
}
複製代碼
如下都將以 api_2指稱 獲取當前熱映更多電影列表api接口ajax
信息 | 說明 |
---|---|
功能 | 獲取hot更多電影列表 |
URL | //m.maoyan.com/ajax/moreComingList |
格式 | JSON |
HTTP METHOD | GET |
參數 | 類型 | 必選 | 說明 | 列子 |
---|---|---|---|---|
token | String | false | 登陸以後的憑證 | |
movieIds | String | true | 請求的電影ID,依賴初始化接口的接口返回字段movieIds | "1214652,1229799,1251606" |
字段 | 類型 | 說明 |
---|---|---|
coming | Array | 更多電影列表 |
//m.maoyan.com/ajax/moreComingList?token=&movieIds=1214652%2C1229799%2C1251606%2C1215114json
{
"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。axios
有朋友關注api_2接口依賴於api_1接口,貓眼的api就是這麼設計的,api_1接口返回了部分電影列表、所有的電影id和電影總數,api_2接口請求只需傳遞電影id就能夠了。其餘公司設計的api接口請求參數可能就是offset和limit。api
要進行接口合併,無非要解決兩個問題, 判斷接口、處理數據
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函數的醜陋封裝,沒有作錯誤處理,(逃
由上文可知,咱們最終的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.一、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()
}
})
複製代碼
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: 天天水一篇,生活樂無邊。