How Axios cancels duplicate and useless requests

Time:2021-6-12

preface

In the development, we often encounter various problems caused by repeated interface requests.

For repeated get requests, it will lead to multiple page updates, page jitter, and affect the user experience.

For repeated post requests, two records will be generated on the server side (for example, two order records).

If the current page request is switched to the next route before the response is completed, these requests will not be terminated until the response returns.

Whether from the perspective of user experience or business rigor, canceling useless requests really needs to be avoided.

Of course, we can use page loading to avoid the user’s next operation, but this article only discusses how to cancel these useless requests.

Canceltoken of Axios

Axios is a mainstream HTTP request library, which provides two ways to cancel requests.

The cancel token and cancel method are generated through axios.canceltoken.source


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.');

Generate cancellation function through Axios. Canceltoken constructor


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 parameter
 cancel = c;
 })
});

// cancel the request
cancel();

It should be noted that when catching exceptions in catch, Axios. Iscancel() should be used to determine whether the current request is actively cancelled, so as to distinguish common exception logic.

Encapsulate cancel request logic

There are two kinds of cancellation requests above. Either one is OK. The second one is used here.

There are two scenarios for cancelling a request

  • When the request method, request path URL and request parameters (get as parameters and post as data) are the same, it can be considered that the same request has been sent many times and the previous request needs to be cancelled
  • When a route is switched, it is necessary to cancel the unfinished requests in the previous route

We encapsulate several methods:

//Declare a map to store the identification and cancellation functions for each request
const pending = new Map()
/**
 *Add request
 * @param {Object} config 
 */
const addPending = (config) => {
 const url = [
 config.method,
 config.url,
 qs.stringify(config.params),
 qs.stringify(config.data)
 ].join('&')
 config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
 if (! Pending. Has (URL)) {// if there is no current request in pending, add it in
  pending.set(url, cancel)
 }
 })
}
/**
 *Remove request
 * @param {Object} config 
 */
const removePending = (config) => {
 const url = [
 config.method,
 config.url,
 qs.stringify(config.params),
 qs.stringify(config.data)
 ].join('&')
 If (pending. Has (URL)) {// if the current request ID exists in pending, you need to cancel the current request and remove it
 const cancel = pending.get(url)
 cancel(url)
 pending.delete(url)
 }
}
/**
 *Clear request in pending (called when route jumps)
 */
export const clearPending = () => {
 for (const [url, cancel] of pending) {
 cancel(url)
 }
 pending.clear()
}

Map is a new data structure in ES6. It provides many methods and is easy to operate. It is suitable for the current scene. If you are not familiar with ECMAScript 6 can view the entry.

When assigning a value to config.canceltoken, you need to determine whether the current request has used the canceltoken in the business code

QS is a special library for converting object and string parameters. It was originally created and maintained by TJ, and is also a parameter serialization library recommended by Axios. Our purpose here is simply to convert the parameter object into a string to facilitate splicing.

The map structure deploys the symbol.iterator attribute by default. You can use the for… Of loop to get the key name and value directly. Of course, you can also use the for… In loop.

Use in Axios interceptor

The main method has been written, just add it to the Axios interceptor.

axios.interceptors.request.use(config => {
 Removepending (options) // before the request starts, check and cancel the previous request
 Addpending (options) // adds the current request to pending
 // other code before request
 return config
}, error => {
 return Promise.reject(error)
})

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

Add the clearpending() method to the Vue routing hook function


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

Test results

Finally, we can test in the browser and switch the network state of the control panel in chrome to slow 3G to simulate the slow network speed.

We take out the loading or disabled attribute of the query button to facilitate testing

As you can see from the control panel above, the request whose red status is cancelled is the cancelled request.

The above code is reflected in e-admin Vue (a RBAC permission model built with Vue + element UI + vue-cli3) or e-admin react (a RBAC permission model built with react + antd + create react APP). Welcome star.

summary

The above is the whole content of this article, I hope the content of this article has a certain reference learning value for your study or work, thank you for your support to developer.