Borrow digifriend (orange someone) preface explanation: speaking of this repeated request, the feeling is used less, psychological always have how a kind of thought even if the request again and again how, the server will collapse? Will the page hang up? Obviously not. Don’t be surprised. Hahaha. Besides, why would there be so many repeated requests? It’s impossible.

And do cancel repeated request operation, in fact, after the cancellation of the request is likely to reach the back end, but the front-end browser does not deal with it, but, alas, we still have to do work, no, must do, so called in case, rigorous, procedural monkey needs rigorous!!

There are two common scenarios in which duplicate requests occur:

  • Clicking a button in quick succession, if the button is not controlled, will make a repeat request, assuming that the request is to generate an order, then two orders will be generated, which is a terrible thing. Of course, the front end usually has some state control over this button, and the back end has some idempotent control or something, so this is a hypothetical scenario, but it could happen.
  • For list data, there may be frequent switching queries in the TAB status bar, which can also generate repeated requests if the request response is slow. Of course, many lists are now cached, such as Vue<keep-alive />.

Is:

Identify duplicate requests and store them in the queue

First we need to collect the interfaces in the requests and determine which requests are duplicate so that we can cancel them. How? Very simple, as long as the request address, request mode, request parameters are the same, then we can think of the same. The data structure in the queue that we are storing should obviously be in the form of key-value pairs, which we select the Map object to operate on.

// axios.js const pendingMap = new Map(); /** * generate a unique key for each request * @param {*} config * @returns string */ function pendingKey (config) {let {url, method, params, data} = config; if(typeof data === 'string') data = JSON.parse(data); Return [url, method, json.stringify (params), json.stringify (data)]. Join ('&'); } /** * stores a unique value for each request, i.e., the cancel() method, Function addPending(config) {const pendingKey = getPendingKey(config); config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => { if (! pendingMap.has(pendingKey)) { pendingMap.set(pendingKey, cancel); }}); }Copy the code

Cancel duplicate requests and exit the delete queue

// axios.js /** * Remove duplicate requests * @param {*} config */ function removePending(config) {const pendingKey = getPendingKey(config); if (pendingMap.has(pendingKey)) { const cancelToken = pendingMap.get(pendingKey); cancelToken(pendingKey); pendingMap.delete(pendingKey); }}Copy the code

Adding interceptors

// axios.js function myAxios(axiosConfig) { const service = axios.create({ baseURL: 'http://localhost:8888', // set the uniform request prefix timeout: 10000, // set the uniform timeout period}); service.interceptors.request.use( config => { removePending(config); addPending(config); return config; }, error => { return Promise.reject(error); }); service.interceptors.response.use( response => { removePending(response.config); return response; }, error => { error.config && removePending(error.config); return Promise.reject(error); }); return service(axiosConfig) }Copy the code

Let’s simply simulate making three repeated requests in a row in the getList() method mentioned above, and then set the browser to 3G mode to see the effect.

// App.vue function getList() { getListAPI().then(res => {console.log(res)}) setTimeout(() => { getListAPI().then(res =>  {console.log(res)}) }, 200); setTimeout(() => { getListAPI().then(res => {console.log(res)}) }, 400); }Copy the code

It’s important to note that it saysCancel the interface being requested“Indicates that the interface may have reached the back end, but the back end is slow, so if you have a fast interface, it’s hard to see the effect. If you build your own service, you can see the effect by simply returning the delay through the interface. Or you can adjust the network speed through the browser’s Network.

We should also have a reasonable handling of cancelled requests, not just ignore them, as far as possible to the controllable bottom of the code, it will be classified as exceptions, as described below (^ω^).

Configuration (some interfaces require repeated requests: config.repeat_request_cancel)

The reason why it is configured to cancel repeated requests, because there may be some special abnormal scenarios, is the need for repeated requests, such as input real-time search, real-time update data, and so on, but it is possible. ( ̄y▽ ̄)~*

// request interceptor service.interceptors.request.use( config => { if (config.method === 'upload') { config = { ... config, ... { method: 'post', data: config.data, methodType: 'upload', headers: { 'Content-Type': 'multipart/form-data' // Need to specify the upload method}, transformRequest: [function() { return config.data }] } } } removePending(config) config.repeat_request_cancel && addPending(config) return config }, error => { // do something with request error console.log('error', error) // for debug return Promise.reject(error) } )Copy the code

We added a custom configuration parameter to the above. Now each API method has two parameters. The first parameter passes some of the original axios configuration, and the second parameter is our own custom parameter. For example, we define repeat_request_cancel to control whether the function of canceling repeated requests is enabled. We will be able to add more features in the future, which is equivalent to customizing every API method, isn’t it great!!

- list / / / / marketing information management configuration repeat_request_cancel Boolean type to determine the export function getProductElementInfoUrlByReq (data, loading = true) { return request({ url: '/xxxxx/xxxxxxx', method: 'post', data: data, loading, repeat_request_cancel: true }) }Copy the code

over!