-----寫在前面-----
家園的面試項目接近尾聲了,剩下一個大模塊(響應式布局)和兩個小功能(下拉到一定程度獲取新的信息、持續監聽返回數據,當有更新時在頁面上方提示)
聽起來下拉到某個位置獲取新信息是不難,但今天就遇到了兩個問題:
1. 下拉過程中會不斷發起url相同的請求,可能會有被拉黑的風險,並且影響實際性能。最重要的,在then()方法中會將返回數據稍做處理后添加進組件數據,並且會驅動Vue更新DOM,
因為用的v-for來填充數據,這樣同一條數據就會被渲染兩次
2.ReadHub除了topic欄外,其余四個欄目下拉獲取更新數據的api接口地址中的參數是時間戳!!而且返回的數據長度也不同
這就導致除了topic以外的欄目在獲取更新數據后還要和已有的數據進行比對,不能重復,目前的想法是
在負責更新數據的axios.then()方法中,detail(存儲所有數據)轉set結構,然后把新返回的數據push進去,再轉回數組(也可以不轉回去?)
⬆⬆⬆⬆⬆這個想法無法執行,因為很神奇的,同樣的api接口可能返回兩種不同格式的數據
第0條和第10條的數據是一樣的(以此類推...)。而且我暫時沒有找到剩下的四個欄目,更新列表發起的請求地址中的時間戳是哪里來的??
(topic欄目是直接根據未加載時列表最下方的一條數據的order來請求的)
而且這個時間戳也沒有規律啥的...
這篇博客主要解決問題1,即攔截相同url的axios請求,網上教程是一堆,但好像大家都是從同一份魔改出來的?因此我頭皮發麻的想了好久,在思否的提問只有21個瀏覽...
推薦閱讀Axios的中文文檔
首先需要明白攔截器的工作原理,axios中內置了兩個攔截器,請求攔截器與響應攔截器,分別通過以下兩個方法調用
axios.interceptors.request.use()
axios.interceptors.response.use()
攔截器的觸發:
對於單個請求來說,在請求發送后會觸發request攔截器進行攔截。
因此可以有以下思路,建立一個空數組,第一次請求成功發送后將本次請求的url保存起來,下一次再次發送請求,會先在請求攔截器中檢驗這一請求的url是否在這個數組中被保存了,
如果是,則取消本次請求(AXIOS提供了cancelToken來取消請求,詳見后文)。
如果有需要的話,在響應攔截器中,在成功返回響應后將本次請求的url從數組中去掉,以便后續的使用,這一情況適用於防止用戶多次點擊發送重復請求?即這個接口后面還有可能用到
let pending = []; //聲明一個數組用於存儲每個請求的取消函數和axios標識
let cancelToken = axios.CancelToken; let removePending = (config) => { // console.log(config);
for(let i in pending){ if(pending[i].url === axios.defaults.baseURL+config.url) { //在當前請求在數組中存在時執行取消函數
pending[i].f(); //執行取消操作
//pending.splice(i, 1); 根據具體情況決定是否在這里就把pending去掉 console.log(pending[i].url); } } }
請求攔截器與響應攔截器:
axios.interceptors.request.use(config => { removePending(config); //在一個axios發送前執行一下判定操作,在removePending中執行取消操作
// console.log(config.url);
config.cancelToken = new cancelToken(function executor(c){//本次axios請求的配置添加cancelToken
pending.push({ // url: config.url,
url: axios.defaults.baseURL+config.url, f:c }); // console.log(axios.defaults.baseURL+config.url);
//將本次的url添加到pending中,因此對於某個url第一次發起的請求不會被取消,因為還沒有配置取消函數
}); return Promise.resolve(config); }, error => { return Promise.reject(error) }) axios.interceptors.response.use(data => { // removePending(data.config); //在一個axios響應后再執行一下取消操作,把已經完成的請求從pending中移除
// console.log(data.config);//如果返回undefined說明被攔截了
return Promise.resolve(data) }, error => { //加載失敗
return {'data':{}} })
這里的詳解見上面的axios中文文檔哈,如果懶得看只要知道這里的c是new cancelToken構造器生成的取消函數就行。
注意這里兩行不同的url,使用上面一行會導致無法攔截,因為項目前面手動設置了axios.defaults.baseURL,導致這里傳入的url如果不加上baseURL,就只會是/topic?lastCursor=xxxxxx&pageSize=20,
但在pending數組⬇中的則是完整的url,就會導致url不匹配從而無法攔截。
建議把這里注釋掉的控制台打印代碼好好運行幾遍~