Why do we need to cancel?

We have a common business scene, the user clicks a data submission, users frequently switching a large quantity of data table, in poor network environment, there will be some abnormal situation, of course, all kinds of UI library provide loading condition can help us to solve the above problems, and can be solved by being part of the problem, but we today from another aspect, CancelToken cancels the last repeated request using Axios cancelToken.

How do we cancel?

Take a look at the cancelToken code in the official AIxOS documentation

Method 1: Cancel tokens can be created using the canceltoken. source factory method, like this:

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

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

Method 2: You can also create the Cancel token by passing an executor function to the CancelToken constructor:

const CancelToken = axios.CancelToken;
let cancel;

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

How to use it in our project?

The more common approach in our project is to use interceptors.

Of course, we need to define a map object to store the related values. (Map is a new object for ES6. If you are not familiar with ES6, please read Ruan Yifong’s Introduction to ECMAScript 6

// Store pending requests (handle multiple requests)
const pendingRequest = new Map(a)Copy the code

Second, you need to encapsulate the functions of some helper classes

  • GenerateRequestKey generates a unique key for repeated requests
import qs from 'qs'
// Generate a unique key for the request
const generateRequestKey = (config = {}) = > {
  // Generate a unique key from the url, method, params, data, which is used to determine whether the request is repeated
  // Params is the GET request parameter, data is the POST request parameter
  const { url, method, params, data } = config
  return [url, method, qs.stringify(params), qs.stringify(data)].join('&')}Copy the code
  • AddPendingRequest saves repeated requests topendingRequestIn the
// addPendingRequest adds repeated requests to pendingRequest
const addPendingRequest = (config) = > {
  const key = generateRequestKey(config)
  if(! pendingRequest.has(key)) {// Check whether a key exists in pendingRequest
    config.cancelToken = new axios.CancelToken(cancel= > {
      pendingRequest.set(key, cancel) // Save key and cancel as key-value pairs}}})Copy the code
  • Cancel the duplicate request and set thependingRequestRemove the
// removePendingRequest Cancels duplicate requests
const removePendingRequest = (config) = > {
  const key = generateRequestKey(config)
  if (pendingRequest.has(key)) { // Check whether a key exists in pendingRequest
    const cancelToken = pendingRequest.get(key)
    cancelToken(key) // Cancel the previously sent request
    pendingRequest.delete(key)Delete the requestKey from the request object}}Copy the code

The complete code

import axios from 'axios'
import qs from 'qs'

// Store pending requests (handle multiple requests)
const pendingRequest = new Map(a)// Generate a unique key for the request
const generateRequestKey = (config = {}) = > {
  // Generate a unique key from the url, method, params, data, which is used to determine whether the request is repeated
  // Params is the GET request parameter, data is the POST request parameter
  const { url, method, params, data } = config
  return [url, method, qs.stringify(params), qs.stringify(data)].join('&')}// Add the repeated request to pendingRequest
const addPendingRequest = (config) = > {
  const key = generateRequestKey(config)
  if(! pendingRequest.has(key)) { config.cancelToken =new axios.CancelToken(cancel= > {
      pendingRequest.set(key, cancel)
    })
  }
}

// Cancel duplicate requests
const removePendingRequest = (config) = > {
  const key = generateRequestKey(config)
  if (pendingRequest.has(key)) {
    const cancelToken = pendingRequest.get(key)
    cancelToken(key) // Cancel the previously sent request
    pendingRequest.delete(key)Delete the requestKey from the request object}}// Request interceptor
service.interceptors.request.use(
  config= > {
    // Process repeated requests
    removePendingRequest(config)
    addPendingRequest(config)

    return config
  },
  error= > {
    // Request processing error
    return Promise.reject(error)
  }
)

// Response interceptor
service.interceptors.response.use(
  response= > {
    // Remove duplicate requests
    removePendingRequest(response.config)
    
    return res
  },
  error= > {
    // Exception console for troubleshooting
    console.log('error', error)
    // Remove duplicate requests
    removePendingRequest(error.config || {})
    
    return Promise.reject(error)
  }
)
Copy the code

Third, the end

If the code needs to be corrected and modified, welcome to comment and leave a message, I will actively reply.