Make writing a habit together! This is the 14th day of my participation in the “Gold Digging Day New Plan · April More Text Challenge”. Click here for more details.

In a project, we might need to ‘shake off’ requests. The main purpose is to prevent users from repeatedly clicking a button in a short period of time in some cases, resulting in repeated requests from the front end and the back end. Common situations:

PC – Double clicking the search button/submit the form may trigger two search requests/double submission of data

Mobile terminal – because the mobile terminal does not click delay, it is very easy to cause misoperation or multiple operations, resulting in repeated requests

It is possible that a loading mask layer will still occur, so we need to consider ways to prevent repeated requests on the front end.

First we need to take a look at the cancelToken API in the AXIos library, which is the core API for canceling interface requests. There are two main methods used in the official website document, the code is as follows:

Method 1: Passaxios.CancelToken.sourceGenerates a cancel tokentokenAnd cancel methodscancel

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 {
    // handle error}}); axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
Copy the code

Method 2: Passaxios.CancelTokenThe constructor generates the cancel function

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parametercancel = c; })});// cancel the request
cancel();
Copy the code

Note that when an exception is caught in a catch, axios.iscancel () should be used to determine whether the current request was actively cancelled to distinguish ordinary exception logic.

Final packaging

Package 1

// List of requests in progress
let reqList = []

/** * prevents duplicate requests *@param {array} reqList- Request cache list *@param {string} url- Current requested address *@param {function} cancel- Request interrupt function *@param {string} errorMessage- Error message to be displayed when a request is interrupted */
const stopRepeatRequest = function (reqList, url, cancel, errorMessage) {
  const errorMsg = errorMessage || ' '
  for (let i = 0; i < reqList.length; i++) {
    if (reqList[i] === url) {
      cancel(errorMsg)
      return
    }
  }
  reqList.push(url)
}

/** * allows a request to proceed *@param {array} ReqList List of all requests@param {string} Url Request address */
const allowRequest = function (reqList, url) {
  for (let i = 0; i < reqList.length; i++) {
    if (reqList[i] === url) {
      reqList.splice(i, 1)
      break}}}const service = axios.create()

// Request interceptor
service.interceptors.request.use(
  config= > {
	let cancel
  	// Set the cancelToken object
    config.cancelToken = new axios.CancelToken(function(c) {
    	cancel = c
    })
    // Prevent duplicate requests. The same request will not be made when the previous request is incomplete
    stopRepeatRequest(reqList, config.url, cancel, `${config.url}The request was interrupted)
    return config
  },
  err= > Promise.reject(err)
)

// Response interceptor
service.interceptors.response.use(
  response= > {
    // Add delay, the same request cannot be sent again in a short time
    setTimeout(() = > {
      allowRequest(reqList, response.config.url)
    }, 1000)
    / /... Subsequent operations after a successful request
    // successHandler(response)
  },
  error= > {
    if (axios.isCancel(thrown)) {
      console.log(thrown.message);
    } else {
      // Add delay, the same request cannot be sent again in a short time
      setTimeout(() = > {
        allowRequest(reqList, error.config.url)
      }, 1000)}/ /... Follow-up operations after a request fails
    // errorHandler(error)})Copy the code

Enclose 2

axios.interceptors.request.use(config= > {
  removePending(options) // Check and cancel the previous request before the request starts
  addPending(options) // Add the current request to Pending
  // other code before request
  return config
}, error= > {
  return Promise.reject(error)
})

axios.interceptors.response.use(response= > {
  removePending(response) // Remove the request after the request is complete
  return response
}, error= > {
  if (axios.isCancel(error)) {
    console.log('repeated request: ' + error.message)
  } else {
    // handle error code
  }
  return Promise.reject(error)
})

axios.interceptors.request.use(config= > {
  removePending(options) // Check and cancel the previous request before the request starts
  addPending(options) // Add the current request to Pending
  // other code before request
  return config
}, error= > {
  return Promise.reject(error)
})

axios.interceptors.response.use(response= > {
  removePending(response) // Remove the request after the request is complete
  return response
}, error= > {
  if (axios.isCancel(error)) {
    console.log('repeated request: ' + error.message)
  } else {
    // handle error code
  }
  return Promise.reject(error)
})

router.beforeEach((to, from, next) = > {
  clearPending()
  // ...
  next()
})
Copy the code