最近作的項目有一個奇葩問題,項目作完後交給甲方,因爲甲方數據庫比咱們模擬的庫在數據量上大好多(單表有幾個億的量)。直接致使接口請求的時間都在30s以上。。。前端
固然數據的優化只能交給後端的同事去作了。可是目前最主要的任務是提供一個能看的前端頁面給甲方驗收。ios
請求慢的問題暴露了前端的不少缺陷。在補充了加載提示等功能後,用戶大量的重複點擊產生的重複接口請求致使相同的數據在請求結束後蜂擁而來。數據庫
網上找了一些博主的方法(見文未連接),所有都是攔截了前面的請求。好比說發了一個請求a
, 在 a 尚未完成時,又發了一個與 a 同樣的請求 a2
,博主們的方法是取消了請求a
只保留a2
axios
以上方法在接口快的時候是不會有問題的。可是接口慢的時候,a
接口都快要請求完成了,這時給它來了個取消。就有點不合理。segmentfault
因此我如今的作法是取消後來的a2
,保留a
。後端
爬一爬axios
官方文檔傳關門,要取消一個正在發出或已發出可是尚未返回數據的請求,用到的是axios.CancelToken
這個對像裏面的方法,以下:數組
const CancelToken = axios.CancelToken; const source = CancelToken.source(); axios.get('/user/12345', { cancelToken: source.token }).catch(function(thrown) { if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // 處理錯誤 } }); axios.post('/user/12345', { name: 'new name' }, { cancelToken: source.token }) // 取消請求(message 參數是可選的) source.cancel('Operation canceled by the user.');
const CancelToken = axios.CancelToken; let cancel; axios.get('/user/12345', { cancelToken: new CancelToken(function executor(c) { // executor 函數接收一個 cancel 函數做爲參數 cancel = c; }) }); // cancel the request cancel();
第一種方法是多個請求共用一個token,適合在某一時間同時取消全部請求,第二種方法每一個請求有獨立的token,適合每一個請求分狀況是否進行單獨取消。函數
顯然本次需求要用第二種方法。post
核心方法就是在請求時將請求信息存在一個數組裏,而後在請求結速以後在這個數組中移除。下次再發請求時就在數組裏找是否存在相同的請求,若是存在,那麼取消本次請求。測試
參看axios
文檔,在請求攔截
與響應攔截
都會反回請求的原始數據。
// 添加請求攔截器 // config中有 url, data, params等信息 axios.interceptors.request.use(function (config) { return config; }); // 添加響應攔截器 // 其中response.config與請求攔截的config是同樣的 axios.interceptors.response.use(function (response) { return response; });
const CancelToken = axios.CancelToken let requestQueue = [] // 請求攔截調用 function handleRequest({ config }) { // 提取四個參數用於區分相同的請求 const { url, method, data = {}, params = {} } = config; const jData = JSON.stringify(data),jParams = JSON.stringify(params) const panding = requestQueue.filter(item => { return item.url === url && item.method === method && item.data === jData && item.params === jParams }) if(panding.length){ // 這裏是重點,實例化CancelToken時,對參數 c 進行當即調用,便可當即取消當前請求 config.cancelToken = new CancelToken(c => c(`重複的請求被主動攔截: ${url} + ${jData} + ${jParams}`)) }else{ // 若是請求不存在,將數據轉爲JSON字符串格式,後面比較好對比 requestQueue.push({ url, data: jData, params: jParams, method, }) } } // 響應攔截調用 function handleResponse({ config }) { const { url, data = JSON.stringify({}), params = JSON.stringify({}) } = config let reqQueue = requestQueue.filter(item => { return item.url !== url && item.data !== data && item.params !== params }) requestQueue = reqQueue }
// 請求攔截 axios.interceptors.request.use(function (config) { handleRequest({ config }) return config; }); // 響應攔截器 axios.interceptors.response.use(function (response) { handleResponse({ config: response.config }) return response; });
試運行結果
CancelToken
方法,其實文檔沒有詳細說明清楚何時能夠調用這個方法,致使不少開發者覺得只能在panding狀太下才可使用,通過個人測試,在請求攔截中就能夠調用cancel。Cancel{message: 'url'}
這個信息。找不到緣由。本次更改在寫博文時沒有通過生產檢驗,歡迎你們幫我找找bug
參考: