之前我寫了一篇文章,分享了自己的專案中對于介面管理的方法,總結下來就是:定義介面檔案--withAxios匯出--呼叫介面方法,這樣實作了介面的統一管理和呼叫介面的語意化與簡單化,
根據在專案的使用,發現有以下問題需要優化:
- withAxios匯出的介面方法物件對編輯器來說是不透明的,所以代碼提示功能缺失,
- 同一個方法呼叫多次,如何保證組件總是獲取到最后一次的回傳資訊,
根據以上問題,采用了以下解決方案:
- 使用typescript的泛型解決,
- 呼叫同一個方法時,取消掉上次未完成的請求,這里使用axios的cancel方法,實作思路是在回傳的方法物件中增加一個`${name}Cancel`的方法,保存取消上一次方法的回呼,下次請求時固定呼叫這個取消方法以保證本次請求是當前唯一一個請求,(這里只提供axios層面的解決辦法,不討論其他辦法,比如采用redux-saga的話可以使用takeLatest解決)
通過代碼展示一下(React專案):
service.ts
import { IApiItem } from '@/configs/api/declares';
import withAxios from '@/utils/withAxios';
const api: IApiItem[] = [
{ name: 'getSummary', url: 'http://xx:8000/api/getSummary' },
{ name: 'getDetail', url: 'http://xx:8000/api/getDetail' },
{ name: 'getDetailChildren', url: 'http://xx:8000/api/getDetailChildren' },
{ name: 'getCurrentUser', url: 'http://xx:8000/api/getCurrentUser' },
];
interface IProdMonitorApi {
getSummary: any;
getDetail: any;
getDetailChildren: any;
getCurrentUser: any;
}
export default withAxios<IProdMonitorApi>(api);
withAxios.ts
function withAxios<T>(apiConfig: IApiItem[], usePassportOrigin: boolean = false): T { const serviceMap = {} as T; apiConfig.map(({ name, url, method = 'get', ...rest }: IApiItem) => { return (serviceMap[name] = async function(data =https://www.cnblogs.com/zczhangcui/p/ {}) { if (serviceMap[`${name}Cancel`] && typeof serviceMap[`${name}Cancel`] === 'function') { serviceMap[`${name}Cancel`](); } const source = axios.CancelToken.source(); serviceMap[`${name}Cancel`] = () => { source.cancel(`已取消上次未完成請求:${name}`); }; rest.cancelToken = source.token; let key = 'params'; const apiMethod = method.toLowerCase(); if (apiMethod === 'post' || apiMethod === 'put') { key = 'data'; } let fetchUrl = url; if (url.indexOf('http') !== 0) { fetchUrl = usePassportOrigin ? NetworkUtils.passportOrigin + url : NetworkUtils.serverOrigin + url; } return axios({ method, url: fetchUrl, [key]: data, fetchName: name, ...rest, } as AxiosRequestConfig); }); }); return serviceMap; } export default withAxios;
在需要使用介面的地方:
import Service from "./service.ts"
Service.getSummary(requestParams).then(...)
說明:
- 使用泛型雖然有了代碼提示,但是額外增加了編碼量,因為要手動維護一個方法介面,有利有弊吧,通過ts我還沒有找到更好的方法,同事之前有過一個解決辦法:介面管理使用物件的形式,然后withAxios修改這個物件各屬性的getter,將getter指向通過axios包裝后的方法,最終實作了本文相同的呼叫方式和代碼提示,但這種方法有點hack的感覺,
- cancel掉上一個介面這種方式保證了資料總是來源于最后一個請求介面,但有時可能會出現問題,比如:在同一個頁面需要展示兩種用戶:common用戶和admin用戶,后端給的介面是/api/v1/user,當引數type=1時為common,type=2時為admin,如果我們把這個介面定義為一個方法getUser,在這個頁面會同時發出兩個請求:Service.getUser({type:1}),Service.getUser({type:2}),但是,由于withAxios會取消上一個相同方法的請求,那么很可能有一個請求被取消,解決辦法是在service中定義為兩種方法:getCommonUser和getAdminUser,將type直接寫入url中,這樣也符合我們語意化的目標,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/165102.html
標籤:JavaScript
上一篇:js 回呼地獄的另類解決方案嘗試
