I was wrong about how to prevent multiple requests from being overwritten by axios. I was wrong about how to prevent multiple requests from being overwritten by AXIos. (Some of the content of the previous post has also been revised accordingly.)

In this paper, the cause of

Regarding the first question mentioned in the previous post:

List shows there are multiple screening items on a page, when the user operation too frequent, in the first screening items when screening results have not yet returned to the selection of the second item selection operation, if the first request takes a long, long to the second request return values have returned to the first didn’t return a request, it will appear, The final rendered list is the result of the first filter, not the result of the second filter we want.

In fact, canceling the request is the most appropriate method for this problem. If loading method is used for this problem, it will be very unfriendly in terms of interaction, because THEN I have to wait for the return of the first filtering result before carrying out the second filtering, but the first filtering result is completely unnecessary from the user’s point of view. Therefore, it is best to directly cancel the first filtering request, so that users do not perceive.

In response to the second question from the previous article: If you submit the same creation request for many times, the effect of using cancellation request is not so ideal strictly, because the back end still receives two creation requests and does not terminate the operation because of the cancellation request of the front end. Therefore, the error will still be reported. As mentioned in the previous article, loading is the most friendly way to overwrite the page. The user does not have the opportunity to submit a second creation request, but in the last article I said that this solution is not that good encapsulation, now I find that there is a good solution.

Set the loading mask of the current operation module to true before sending the request and to false after receiving the return value of the request (whether it succeeds or fails). However, each module maintains such a variable to worry about what to open and when to close, and write a V-loading, so that the ease of use and reuse is too low, this paper provides a package scheme, just for reference, ask light jet

Get into the business

  1. Start by adding the declaration to the axios wrapper file
import { Loading } from 'element-ui'
let loadingInstance
Copy the code
  1. Then add a judgment to the Request interceptor
// Check whether the request config contains loadingOptions, that is, whether to add loading processing to the request. The format is Object
// loadingOptions is the loadingOptions configuration of elementUI
if (config.loadingOptions) loadingInstance = Loading.service(config.loadingOptions)
Copy the code

  1. Add an extra config to the default parameter in the request definition (previously only params was accepted)
import axios from '@/plugins/axios'

export const getUserList = (queryParams, config) = > {
  return axios.get('/path/path', queryParams, config)
}
Copy the code
  1. Then add the upper and lower sections to the Request interceptor error handler, to the Response interceptor error handler, and to the Response interceptor error handler
if (loadingInstance) loadingInstance.close()
Copy the code
  1. Add a unique ID to the DOM you want to overwrite loading, such as “soleId”, and then pass an extra config parameter to the request as follows:
async toGetUserList() {
  let res
  // The first parameter is the request pass parameter. The second parameter is the request configuration, which tells the interceptor that I want to load the request
  res = await getUserList({ teamId: 5 }, { loadingOptions: { target: '#soleId'}})if (res) this.userList = JSON.parse(JSON.stringify(res.data))
}
Copy the code

The method is very simple. In this way, there is no need to worry about the processing timing of loading’s control variable, and no need to maintain this control variable, which can still improve some development efficiency and maintainability.

Post the full axios code at the end

import axios from 'axios'
import { Loading } from 'element-ui'

// Set baseURL to determine whether the current environment is production. If not, set your own apiURL
letbaseURL = process.env.NODE_ENV ! = ='production' ? '/' : '/'
let config = {
  baseURL,
  timeout: 60 * 1000 // Request timeout
}

let loadingInstance

const _axios = axios.create(config)

let pendingQueue = new Map(a)let CancelToken = axios.CancelToken
// HTTP request interceptor
_axios.interceptors.request.use(
  function (config) {
    // Do something before request is sent
    if (config.loadingOptions) loadingInstance = Loading.service(config.loadingOptions)
    // Check whether the request is in the queue before it is initiated. If so, cancel pending requests in the queue
    judgePendingFunc(config)
    // Set the pending queue to current
    config.cancelToken = new CancelToken(cb= > {
      pendingQueue.set(`${config.method}->${config.url}`, cb)
    })
    if (config.method === 'get') {
      let res = handleGetUrl(config.url, config.params)
      config.url = res.url
      config.params = res.params
    }
    return config
  },
  function (error) {
    // Do something with request error
    console.log(error)
    if (loadingInstance) loadingInstance.close()
    return Promise.reject(error)
  }
)

// HTTP Response interceptor
_axios.interceptors.response.use(
  function (response) {
    // Do something with response data
    if (loadingInstance) loadingInstance.close()
    removeResolvedFunc(response.config)
    console.log(response)
    return response.data
  },
  function (error) {
    // Do something with response error
    console.log(error)
    if (loadingInstance) loadingInstance.close()
    return Promise.reject(error)
  }
)

// Secondary encapsulation method
/** * Receive three parameters, the config parameter is not transmitted *@param {String} url
 * @param {Object} data
 * @param {Object} config* /
const getFn = async (url, data, config = {}) => {
  let params = { params: data, ... config }try {
    return _axios.get(url, params)
  } catch (error) {
    return handleError(error)
  }
}
/** * Receive three parameters, the config parameter is not transmitted *@param {String} url
 * @param {Object} data
 * @param {Object} config* /
const postFn = async (url, data, config = {}) => {
  try {
    return _axios.post(url, data, config)
  } catch (error) {
    return handleError(error)
  }
}
const deleteFn = async (url, data) => {
  try {
    return _axios.delete(url, data)
  } catch (error) {
    return handleError(error)
  }
}
// Catch a request error
function handleError(error) {
  Promise.reject(error)
}
// Determine if the request is in the queue and cancel the request if it is
const judgePendingFunc = function (config) {
  if (pendingQueue.has(`${config.method}->${config.url}`)) {
    pendingQueue.get(`${config.method}->${config.url}`) (the)}}// Delete the request that has been executed from the queue
const removeResolvedFunc = function (config) {
  if (pendingQueue.has(`${config.method}->${config.url}`)) {
    pendingQueue.delete(`${config.method}->${config.url}`)}}// Handle problems caused by functional and non-functional characters being converted in GET requests
const handleGetUrl = function (url, params) {
  if(! params)return { url: url, params: params }
  let parts = []
  let resUrl = url
  let resParams = params
  let keys = Object.keys(params)
  if (keys.length > 0) {
    for (let key of keys) {
      let values = []
      if (Array.isArray(params[key])) {
        values = params[key]
        key += '[]'
      } else values = [params[key]]
      values.forEach(val= > {
        if (val || val === 0)
          parts.push(`The ${encodeURIComponent(key)}=The ${encodeURIComponent(val)}`)})}let serializedParams = parts.join('&')
    if (serializedParams) {
      resUrl += (resUrl.includes('? ')?'&' : '? ') + serializedParams
    }
  }
  return { url: resUrl, params: resParams }
}

export default {
  get: getFn,
  post: postFn,
  delete: deleteFn
}
Copy the code

Just sauce, break it up