axios封裝(二)隊列管理

在某些特定的場景(好比 即時搜索表格分頁),會頻繁的發起ajax請求,而因爲ajax是異步API,因此返回的時序並不可以保證,這時候就須要實現一個ajax隊列,在相同的請求發起時,取消處理上一個請求。javascript

在使用 jquery.ajax 時,能夠比較方便的使用 abort 方式中斷處理ajax返回值,可是因爲 axios 是依賴於 promise 的,致使了只能經過轉換爲 Promsie.reject 的方式中斷處理。具體的代碼以下:java

import axios from 'axios';
import Qs from 'qs';

// 上一篇文章中定義的錯誤處理文件
import httpErrorHandler from './httpErrorHandler';

const instance = axios.create();

// 請求隊列
const queue = [];
// axios內置的中斷ajax的方法
const cancelToken = axios.CancelToken;
// 拼接請求的url和方法,一樣的url+方法能夠視爲相同的請求
const token = (config) =>{
  return `${config.url}_${config.method}`
}
// 中斷重複的請求,並從隊列中移除
const removeQueue = (config) => {
  for(let i=0, size = queue.length; i < size; i++){
    const task = queue[i];
    if(task.token === token(config)) {
      task.cancel();
      queue.splice(i, 1);
    }
  }
}

//添加請求攔截器
instance.interceptors.request.use(config=>{
  removeQueue(config); // 中斷以前的同名請求
  // 添加cancelToken
  config.cancelToken = new cancelToken((c)=>{
    queue.push({ token: token(config), cancel: c });
});
  return config;
}, error => {
  return Promise.reject(error);
});

//添加響應攔截器
instance.interceptors.response.use(response=>{
  // 在請求完成後,自動移出隊列
  removeQueue(response.config);
  return response.data
}, httpErrorHandler);

/**
 * 封裝後的ajax post方法
 *
 * @param {string} url 請求路徑
 * @param {object} data 請求參數
 * @param {object} config 用戶自定義設置
 * @returns
 */
 function post (url, data, config = {}) => {
  return instance.post(url, data, config)
}

/**
 * 封裝後的ajax get方法
 *
 * @param {string} url 請求路徑
 * @param {object} params 請求參數
 * @param {object} config 用戶自定義設置
 * @returns
 */
 function post (url, params, config = {}) => {
  return instance.get(url, {params}, config)
}

export default {
    post,
    get,
}

隊列應用

隊列通常結合函數防抖使用,在儘可能減小請求次數的狀況下,避免返回值順序的錯誤jquery

$(input).on('input', evt => {
    // 在用戶不斷的輸入過程當中,當暫停輸入100ms才發起ajax,在發起ajax的同時,中斷上一個查詢keyword的ajax
    debounce(()=>{
        get('http://baidu.com', {keyword: evt.target.value})
    })
})


// 定義一個防抖函數
function debounce(fn, step = 100) {
    let timeout = null;
    return function () {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            fn.apply(this, arguments);
        }, step);
    };
}
相關文章
相關標籤/搜索