vue中使用axios對同一個接口連續請求致使返回數據混亂的問題

業務上出現一個問題:若是連續對同一個接口發出請求,參數不一樣,有時候先請求的比後請求的返回數據慢,致使數據順序混亂,或者數據被覆蓋的問題,因此須要控制請求的順序。前端

解決方法:vue

1.直接跟後臺溝通,將全部參數放到數組裏後臺統一接收並返回全部數據再由前端進行數據的拆分使用。ios

2.對於出現返回的數據混亂問題。
假設場景: 頁面中須要對三個部門請求對應的部門人員,三個部門人員的數據爲一個二維數組,連續發送請求,但因爲返回數據的順序不定,致使數組中的數據順序不是按照部門的順序。
解決方法:使用promise.all + axios。vuex

//獲取部門人員的請求
getDepartPerson (departData) {
        let that = this
        return new Promise(function(resolve,reject) {
          that.$axios({
              method: 'get',
              url: ...,
              params: {
                ...
              }
            }).then(res => {
              const data = res.data.map(item => {
                return {
                  value: item.userId,
                  label: item.userName
                }
              })
              resolve(data)
            })
        })
        
      },
      
//使用promise.all控制返回的數據順序
setPersonData() {
        const data = [{
          departId: 1,
          departName: '部門1'
        }, {
          departId: 2,
          departName: '部門2'
        }, {
          departId: 3,
          departName: '部門3'
        }]
        let promise1 = this.getDepartPerson(data[0])
        let promise2 = this.getDepartPerson(data[1])
        let promise3 = this.getDepartPerson(data[2])
        console.log(promise1,promise2,promise3)
        let that = this
        Promise.all([promise1,promise2,promise3]).then(value => {
          console.log(value) //value返回的數據是按順序的
        })
      },

這裏要注意
在promise中this不能指向vue的,因此在promise使用前賦值axios

let that = this

3.對於返回數據出現覆蓋的問題
假設場景:切換菜單的時候老是會向後臺發送同一個請求,不一樣參數。且假設這幾個菜單共用vuex中的一個state,假設從a菜單切換到b菜單中,a返回的數據比b返回的慢,致使覆蓋了state,此時雖然切換到b菜單,可是頁面上的數據是a的數據。數組

解決方法:使用axios中的CancelToken,對於以前的請求進行禁止。promise

//取消接口相同參數不一樣的處於pending狀態下的請求
export const pending = []
let CancelToken = axios.CancelToken
let cancelPending = (config) => {
  for(let i=pending.length-1; i>=0; i--){
    if (!!config) {
      if (pending[i].u === config.url && pending[i].delPending) {
        console.log('delete request')
        pending[i].f() // 取消請求
        pending.splice(i, 1) // 移除當前請求記錄
      }
    } else {
      pending[i].f() // 取消請求
      pending.splice(i, 1) // 移除當前請求記錄
    }
  }
}

接着在請求前進行攔截async

/**
 * 請求前攔截
 */
export function requestSuccessFunc (config) {
  cancelPending(config)
  config.cancelToken = new CancelToken((c) => {
    pending.push({'u': config.url, 'f': c, delPending: config.delPending})
  })
  return config
}

/**
 * 請求結果預處理
 * @param response
 * @returns {Promise<never>}
 */
export function responseSuccessFunc (response) {
  cancelPending(response.config)
}

拓展:若是在切換路由的時候能夠將以前頁面中請求處於pengding狀態的取消this

export function routerAfterEachFunc () {
  // 這裏能夠作路由後操做
  //切換路由時取消以前頁面處於pending的請求
  for(let i=pending.length-1; i>=0; i--){
    pending[i].f() // 取消請求
    pending.splice(i, 1) // 移除當前請求記錄
  }
  console.log(pending)
}

....

const ROUTER = new Router({
  routes: CONST_ROUTER
})
ROUTER.afterEach(routerAfterEachFunc)
export default ROUTER

4.假設這裏不是請求同一個接口,而是上一個接口返回的數據做爲下一個接口請求的參數,這是能夠使用async awaiturl

相關文章
相關標籤/搜索