preface

In development, it is common to encounter various problems caused by repeated interface requests.

Repeated network requests cause the page to be updated for several times, resulting in page jitter, which affects user experience.

For example, if the current page request is switched to another route before the response is complete, those requests will not be aborted until the response is returned.

Preventing duplicate requests is necessary both for user experience and for business rigor.

Implementation approach

** 1. Intercept the current request address (URL + method + parameter) before sending the request;

** 2. Start a request queue to save the current address;

** 3. Check whether there is a current URL in the request queue.

** 4. Cancel the current request if there is a current URL in the request queue.

** 5. If no request is sent, the current URL will be cleared in the request queue when the request data is returned.

1. Usually, we write interface like this:

Request interface file

import { http } from '@/plugin/axios'; // Import request interface HTTP

/ / initialization
export function getInit(params) {
    return http({
        method: 'get'.url: '/xxx/xxx/xx',
        params,
    });
}
Copy the code

Basically, this is where you do the HTTP method;

When you execute the HTTP function, you get all the requested config and return a Promise object.

2. Use it hereaxios, the idea is to execute a request function when the outer layer

Axios.js configuration file

import axios from 'axios';
import { httpRequest, completeRequest } from './options'; // Here is the logical file we want to implement

// Do some request interception in axios
const service = axios.create({
    baseURL: 'xxx/xxx'});// Request interceptor
service.interceptors.request.use(config= > {}, error= > {})

// Response interceptor
service.interceptors.response.use(response= > {
  completeRequest(response); // 2. Execute the request
}, error= >{})export function http(config) { // => config is the request configuration parameter passed
    return httpRequest(config, service); // + 1. Do some logic here
}

Copy the code

3. Prevent network configuration files from being duplicated

options.js

(1) Before sending a request, check whether there is a current request in the request queue (to determine the URL address)

  • The request queue has the current URL address,Cancel the requestreturnpromise.rejectfailure
  • Send request normally without current request.
/** * Responsibilities: prevent duplicate network requests ** /

let list = new Set(a);// 1. Request queue

// Merge method parameter URL address
function getUrl(config = {}) {
  // Get request params parameter Post request data parameter baseURL
  const { url, method, params, data, baseURL = ' ' } = config;
  const urlVal = url.replace(baseURL, ' ');
  return `${urlVal}?${method === 'get' ? getformatObjVal(params) : getformatObjVal(data)}`;
}

// Handle the URL address
const getformatObjVal = (obj) = > {
  obj = typeof obj === 'string' ? JSON.parse(`${obj}`) : obj;
  var str = [];
  for (let p in obj) {
    if(obj.hasOwnProperty(p) && p ! = ='_t') {
      var item = obj[p] === null ? ' ' : obj[p]; / / null
      str.push(encodeURIComponent(p) + '=' + encodeURIComponent(item)); }}return str.join('&');
}

// 2
export function httpRequest(config = {}, axios) {
  const url = getUrl(config); //3. Here we get the URL

  if (list.has(url)) {  // 4. Check whether the request queue has the current URL
    return Promise.reject('In the request'); // 5. Cancel the current request in the request queue, return the Promise failure result
  }
  
  // 6. The request queue does not have the current URL address to send the request and store the URL in the request queue
  list.add(url);
  return Promise.resolve(axios); 
}
Copy the code

(2) Delete the current URL address in the request queue after the request response is returned; (The next request can be sent as normal)

​ options.js

// Request the response back to execute this function
export function completeRequest(response = {}) {
  const { config } = response; // 1. Config can get configuration parameters in response
  const url = getUrl(config); // 2. Obtain the URL
  if (list.has(url)) {
    list.delete(url); // 3. Delete the current request URL from the request queue}}Copy the code

axios.js

import axios from 'axios';
import { httpRequest, completeRequest } from './options'; // Prevent duplicate requests

const service = axios.create({
    baseURL: 'xxx/xxx'});// Request interceptor
service.interceptors.request.use(config= > {}, error= > {})

// Response interceptor
service.interceptors.response.use(response= > {
  completeRequest(response); // 2. Execute + in response to the request
}, error= >{})// Export the request
export function http(config) {
    return httpRequest(config, service);  // 1. Execute before sending the request
}

Copy the code

So far this has been implemented to prevent repeated network requests, but there is still a problem with the response request exception to clear the current URL address in the request queue. If the request is not cleared, the next time it is sent, it will be cancelled.

/** * Clear all request queues */
export function clearRequestList() {
  list = new Set(a);// I'm going to empty it
}
Copy the code

completehttp.jsfile

import axios from 'axios';
import { httpRequest, completeRequest, clearRequestList } from './options'; // Prevent repeated requests +

const service = axios.create({
    baseURL: 'xxx/xxx'});// Request interceptor
service.interceptors.request.use(config= > {}, error= > {})

// Response interceptor
service.interceptors.response.use(response= > {
  completeRequest(response); // 2. Execute the request
}, error= > {
  clearRequestList(); // + 
})


// Export the request
export function http(config) {
    return httpRequest(config, service);  // 1. Execute before sending the request
}
Copy the code

completeoptions.js

/** * Responsibilities: prevent duplicate network requests ** /

let list = new Set(a);// 1. Request queue

// Merge method parameter URL address
function getUrl(config = {}) {
  // Get request params parameter Post request data parameter baseURL
  const { url, method, params, baseURL = ' ' } = config;
  const urlVal = url.replace(baseURL, ' ');
  return `${urlVal}?${method === 'get' ? getformatObjVal(params) : 'post'}`;
}

// Handle the URL address
const getformatObjVal = (obj) = > {
  obj = typeof obj === 'string' ? JSON.parse(`${obj}`) : obj;
  var str = [];
  for (let p in obj) {
    if(obj.hasOwnProperty(p) && p ! = ='_t') {
      var item = obj[p] === null ? ' ' : obj[p]; / / null
      str.push(encodeURIComponent(p) + '=' + encodeURIComponent(item)); }}return str.join('&');
}

// 2
export function httpRequest(config = {}, axios) {
  const url = getUrl(config); //3. Here we get the URL

  if (list.has(url)) {  // 4. Check whether the request queue has the current URL
    return Promise.reject('In the request'); // 5. Cancel the current request in the request queue, return the Promise failure result
  }

  // 6. The request queue does not have the current URL address to send the request and store the URL in the request queue
  list.add(url);
  return Promise.resolve(axios);
}


/** * request the response back to execute this function */
export function completeRequest(response = {}) {
  const { config } = response; // 1. Config can get configuration parameters in response
  const url = getUrl(config); // 2. Obtain the URL
  list.has(url) && list.delete(url); // 3. Delete the current request URL from the request queue
}

/** * Clear all request queues */
export function clearRequestList(error) {
  // Error can get the configuration and do some operations.
  list = new Set(a);// I'm going to empty it
}

Copy the code

This is how I implemented network request prevention. I used CancelToken in AXIos to cancel requests. There will be some problems.

  1. Request files need to be configured, which is unfriendly and cumbersome for the team to develop configurations.
  2. You need to configure it for each requestCancelToken. There are two ways to use it and you can refer to the documentation on the official website