The profile
Axios is one of the request tools commonly used in the development of WebApp, which makes it easier for us to carry out front-end and back-end joint adjustment. Encapsulating a request module in the front-end project can improve efficiency. We can learn how axios is implemented and configured to understand and better use several other request tools of the same type. The following usage scenarios are based on projects developed using the VUE technology stack.
Configuration optimization
1.1 configure a
In our projects, we usually wrap AXIos to allow for rapid development, such as the following:
config.js
import axios from 'axios'
export default axios
Copy the code
http.js
import axios from 'config'
export function post (url, param) {
return axios.post('url', {params:param
} )
}
Copy the code
userInfo.vue
import {post} from 'http.js'
created() {
post('/v1/getPatientDetail').then((res) = > {
// do sth...})}Copy the code
This encapsulation mainly unifies different request methods, but if we have other request methods, such as PUT, delete, etc., then we have to declare definitions, and this way of passing parameters is not free.
In addition, you may encounter that the backend may make uniform changes to some specific business interface names. In this way, if we want to make uniform changes to the interface names, we can only go to the components to make individual changes, which is very inconvenient.
1.2 configuration 2
According to the above problems, let’s optimize the way of encapsulation:
config.js
import axios from 'axios'
export default axios
Copy the code
user.js
import axios from 'config.js'
export const getUserDetail = (params) = > {
retrun axios.post('/v1/getUserDetail', params) } ... .Copy the code
userInfo.vue
import {getUserDetail } from 'user.js'
created() {
getUserDetail({id: '132456'}).then((res) = > {
// do sth...})}Copy the code
According to the different business will be divided into modules, the specific request method will be directly defined in the file, we can be directly called in the component to use, which is very consistent with our needs, so that it is convenient for later maintenance and convenient for us to view the interface document. However, this approach is not perfect, as we need to write a lot of import statements in the component every time we need to request an interface, and an interface that is used repeatedly in multiple components needs to be imported every time.
2.1 Optimization (structure, extraction, unification)
How can we avoid all of the problems we mentioned above and make our requests elegant and easy to maintain?
Based on the above problems, we configure a request module, which is roughly divided into the following three steps:
- We put the interface documents together in a single folder for configuration encapsulation.
- Encapsulates a method that calls an interface uniformly, fetching and calling different interface files with the parameters passed in.
- Register functions with the VUE prototype as plug-ins for global invocation.
./request/config.js
import axios from 'axios'
export default axios
Copy the code
./request/apiModules/user.js
export default {
getPatientDetail : {
url: 'v1/getDetail'.method: 'get'
}
// ...
// ...
}
Copy the code
- This is the url of the interface that we requested and the method that called the interface, and the behavior of the request is described below.
./request/fetch.js
import axios from './config'
// Load the configuration file
const fetchConfig = {}
const requireContext = require.context('./apiModules'.false./\.js$/)
requireContext.keys().forEach(path= > {
let module = path.replace('.js'.' ').replace('/'.' ')
fetchConfig[module] = requireContext(path).default
})
Let fetchConfig = {* user: {* getPatientDetail: {* url: 'v1/getDetail', * method: 'get' *} *} *} * /Copy the code
- In the Webpack environment, we use require.context to dynamically read configuration files from the apiModules directory and store all configuration after reading so that we don’t have to import it every time we create new modules. The same method can be used to dynamically read the configuration of multiple configurations in a scenario where vuEX is configured with multiple modules.
/** * Parses parameters * This function is mainly responsible for parsing the module and apiName * passed into the fetch@param {String} param* /
const fetchParam = param= > {
var valid = /[a-z]+(\.[a-z])+/.test(param)
if(! valid) {throw new Error('[Error in fetch]: The format of the fetch parameter is moduleName. ApiName '.)}else {
return {
moduleName: param.split('. ') [0].apiName: param.split('. ') [1]}}}/** * request function * This function mainly finds the corresponding configuration to initiate the request through the parsed Module and apiName *@param {String} moduleInfo
* @param {any} payload* /
export function fetch(moduleInfo, payload) {
let prefix = ' '
let moduleName = fetchParam(moduleInfo)['moduleName']
let apiName = fetchParam(moduleInfo)['apiName']
// Determine that the incoming module is not found
if(! fetchConfig.hasOwnProperty(moduleName)) {throw new Error(
'[Error in fetch]: module not found in API configuration file ->${moduleName}`)}// The corresponding interface is not found
if(! fetchConfig[moduleName].hasOwnProperty(apiName)) {throw new Error(
'[Error in fetch]: in the module${moduleName}Interface not found in ->${apiName}`)}let fetchInfo = fetchConfig[moduleName][apiName]
let method = fetchInfo['method']
let url = `${prefix}/${fetchInfo['url']}`
let mode = fetchInfo['mode'] // Add a needCancel attribute to headers here.
mode
? (axios.defaults.headers['needCancel'] = true)
: (axios.defaults.headers['needCancel'] = false)
if (method === 'get') {
/ / url: 'v1 / special/template/assess / {id} / {code}' is used to solve the get in the interface with multiple parameters need to be passed.
if (url.indexOf('{')! = = -1) {
let temp = url.match([^ / \ {\}] + \} /) [0]
let param = temp.substring(1, temp.length - 1)
let newUrl = url.replace(/\{[^\)]*\}/g, payload[param])
return axios[method](newUrl)
}
return axios[method](url, {
params: payload
})
} else {
return axios[method](url, payload)
}
}
Copy the code
- By parsing the incoming parameters, we get the url, method, mode and other attributes of the corresponding interface (the mode attribute mainly implements the customization requirements for the interface, as explained in the following section), and finally use AXIos to initiate the request.
- When we separate the request method from the package, if we add a new interface in the development, we only need to modify or add the configuration file in the apiModules, no need to pay attention to other operations, so that we can better develop business.
./request/index.js
import {fetch} from './request/fetch.js'
export default {
install(Vue) {
Vue.prototype.$fetch = fetch
}
}
Copy the code
- Export an object that contains the install function, which puts the FETCH method in the VUE prototype chain so that we can use the
this.$fetch
Without introducing a specific request method.
./main.js
import Vue from 'vue'
import request from './request/index'
Vue.use(request)
Copy the code
- We initially installed Request in the project entry file and finally made it globally available.
In main.js we can see that the Vue. Use method can be used to install plug-ins. Let’s take a look at the use function source code to see how use operates to install some Vue plug-ins on Vue.
The code captured below is vue”version”: “2.6.12”. Use Detailed path
vue/src/core/global-api/use.js
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// additional parameters
const args = toArray(arguments.1)
args.unshift(this)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this}}Copy the code
Each call checks to see if the plug-in exists in the installedPlugins array and returns it if it does. Args.unshift (this) where this points to the VUE class, place it in the parameters array, and then apply calls the install method of the plug-in and passes the args parameter to the Install method. This way, you don’t need to introduce VUE when developing the plug-in to cause the file to be too large. Finally, installedplugins.push (plugin) stores the initialized plug-in into a cache array to avoid repeated initialization.
From the source code, we know that the development of vue-based plug-ins need to implement the install method.
3.1 Optimization (Cancel)
3.1.1 Canceling Repeated Requests on the same Interface
Axios has a wealth of configurations that help us save work and optimize our projects at development time. We have decoupled the interface document from the request method above, where we can customize the method for our project to be used quickly.
We see this scenario all the time in development, especially on mobile. A search service needs to find out the query result in real time according to the user’s input. We capture the user’s input event and re-initiate the request every time new content is entered. This was a waste of our request resources, we didn’t want to initiate a request every time we typed, so we added a 200ms “debounce “wrapper to the input event to avoid triggering too many requests.
However, when our search interface is complex, or we use the interface provided by a third party, such as finding a place name or finding a product, the response is often very slow, and sometimes the delay of 1-2s is normal. In this case, the user enters “Beijing” in the input box, initiates a request, and finds that the user actually wants to search for “Nanjing”, then re-enters “Nanjing”, even though there is 200ms of security, the user still initiates multiple requests. Because the response time of the interface is uncertain, the first request may be faster than the last one, resulting in the embarrassing situation of “Nanjing” being overwritten by “Beijing”.
Therefore, we can add the mechanism of cancel on the basis of anti-shake to the search interface. This is used to manually cancel the previous interface when the same interface has already initiated a request but has not yet responded.
Specific operations are as follows:
./request/apiModules/useInfo.js
export default {
// Verify that the current mobile phone number is registered
checkPatientPhone: {
url: 'v1/patient/verification/phone/{condition}'.method: 'get'.mode: 'search'}}Copy the code
./request/fetch.js
import axios from './config'
export function fetch() {...let mode = fetchInfo['mode']
mode === "search" ? (axios.defaults.headers['needCancel'] = true) : (axios.defaults.headers['needCancel'] = false)... }Copy the code
- We have seen the fetch implementation method in 2.1. The value of corresponding mode is obtained inside the method, and we make a judgment
mode === "search"
If true, add a custom attribute to headers for determination, which we implement in the interceptor.
./request/config.js
import axios from 'axios'
// Intercepts a url string concatenation method as the unique identifier of the interface
function fmtUrl({url, method}) {
return `${url.substr(0, url.lastIndexOf('/'))}&${method}`
}
let pending = [] // Declare an array to store the cancellation function and ajax identifier for each Ajax request
let cancelToken = axios.CancelToken
let removePending = config= > {
if(! config.headers.needCancel)return
const requestName = fmtUrl(config)
for (let p in pending) {
if (pending[p].name === requestName) {
// Execute the function body when the current request exists in the array
pending[p].fn() // Perform the cancel operation
pending.splice(p, 1) // Remove this record from the array}}}// Request interceptor
axios.interceptors.request.use(
config= > {
removePending(config) // Perform a cancel operation before an Ajax send
config.cancelToken = new cancelToken(cancelFn= > {
// The ajax identifier here is a string concatenated with the request address and request, of course you can choose some other way
if (config.headers.needCancel) {
const requestName = fmtUrl(config)
pending.push({ name: requestName, fn: cancelFn })
}
})
return config
},
err= > {
return Promise.reject(err)
}
)
// Response interceptor
axios.interceptors.response.use(
response= > {
removePending(response.config) // Perform a cancel operation after an Ajax response to remove the completed request from pending
return response
},
error= > {
console.log(error)
return Promise.reject(error)
}
)
export default axios
Copy the code
CancelToken takes the exposed method and instantiates it. The instantiation takes an anonymous function as an argument. Inside the anonymous function is the method cancelFn that CancelToken passed to us to cancel the interface.
When we first encounter needCancel === true in the request interceptor, we store the cancellation method and unique interface name obtained after CancelToken is instantiated in a Pending array. When the interface initiates a request again, it goes into the request interceptor and executes removePending, which interrupts the same interface in the array by executing the cancel method. To avoid canceling an interface that has responded successfully in the next request, we also execute the removePending function in the response interceptor to delete the corresponding data in pending for the interface that has responded successfully to avoid repeated operations.
So far, this section has been developed to avoid overwriting results by repeatedly making the same request. If we need this function for other services, we can directly add mode:”search” in the configuration to enable it.
3.1.2 Cancel the same response on the same Interface
Through the above case we found the cancel mechanism can help us optimize web request, can optimize the request that affirmation is to extend some more ideas, can reduce a useless request, after all, the interface can save resources in a shorter time to launch more request, this is real performance optimization.
Using the idea of the cancel function above, we optimized the frequently used interface for returning enumeration data in some projects. We mark some enumerated interfaces with high utilization rate. When they successfully initiate request and respond, we store their data in sessionStorage. Next time the same interface makes request, we cancel the current interface and get the result directly from sessionStorage. After all, getting it locally is much faster than getting it from the server.
Concrete implementation:
./request/apiModules/useInfo.js
export default {
// Get time enumeration
getLibraryDateList: {
url: 'v1/medical/library/date/type/list'.method: 'get'.mode: 'cache'}}Copy the code
./request/fetch.js
import axios from './config'
export function fetch() {...let mode = fetchInfo['mode']
mode === "cache" ? (axios.defaults.headers['needCache'] = true) : (axios.defaults.headers['needCache'] = false)... }Copy the code
The interface configuration is the same as the fetch internal implementation.
./request/config.js
import axios from 'axios'
// Intercepts a url string concatenation method as the unique identifier of the interface
function fmtUrl({url, method}) {
return `${url.substr(0, url.lastIndexOf('/'))}&${method}`
}
let pendingCache = [] // Declare an array to store the cancellation function and ajax identifier for each Ajax request
let cancelCachePending = (config, cacheData) = > {
if(! config.headers.needCache)return
let requestName = fmtUrl(config)
if (cacheData) {
window.sessionStorage.setItem(`${requestName}`.JSON.stringify(cacheData))
}
let requestResult = window.sessionStorage.getItem(`${requestName}`)
if (requestResult) {
for (let p = pendingCache.length - 1; p >= 0; p--) {
if (pendingCache[p].name === requestName) {
// sessionStorage has data, then the cancellation function is triggered directly, and the obtained data is returned
pendingCache[p].fn({
hasLoad: true.result: JSON.parse(requestResult)
})
pendingCache.splice(p, 1) // Remove this record from the array}}}}// Request interceptor
axios.interceptors.request.use(
config= > {
config.cancelToken = new cancelToken(cancelFn= > {
if (config.headers.needCache) {
const requestName = fmtUrl(config)
pendingCache.push({ name: requestName, fn: cancelFn })
cancelCachePending(config)
}
})
return config
},
err= > {
return Promise.reject(err)
}
)
// Response interceptor
axios.interceptors.response.use(
response= > {
// A successful response triggers this function
cancelCachePending(response.config, response.data)
return response
},
error= > {
console.log(error)
return Promise.reject(error)
}
)
export default axios
Copy the code
./components/user.vue
created() {
this.$fetch('userInfo.getLibraryDateList').then((res) = > {
let data = res.data.result
this.dateOptions = Object.freeze(data.map((item) = > ({ label: item.desc, value: item.status })))
}).catch((e) = > {
let { message } = e
if (message.hasLoad) {
let res = message.result
let data = res.result
this.dateOptions = Object.freeze(data.map((item) = > ({ label: item.desc, value: item.status })))
}
})
}
Copy the code
In the request interceptor, we get a cancel function for needCache === true and add it to the pendingCache array. CancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending cancelCachePending Do not cancel any operation.
When the interface responds successfully, the interceptor passes the data to the cancelCachePending function, which stores the data for the next time the same interface requests it. At this time, we need to perform compatibility processing on the request interface. When the result is returned by the cancel interface, promise.reject will be called internally to return the information, so we need to receive data in the catch for operation.
The interface optimization function for the duplicate data cancellation interface that we implemented with the Cancel mechanism has been implemented. We found that just using the CACel mechanism provided in Axios helped us to do a lot of optimization work on the development of the project. Of course, I believe that not only these two solutions, children can implement other functions according to their own business needs.
The principle of analysis
From the configuration of request module to the configuration of cancel in the interceptor, we rely on the application of axios plug-in. In this chapter, we will take a look at the source code of the above mentioned functions. We will not look at the many, but mainly understand how its interceptor and cacelToken are implemented. So it hides some irrelevant code logic. From the source level to understand the implementation of plug-ins, can greatly improve our understanding and mastery of it, so that we are more skilled in the use of easy expansion, and the definition of the request encountered in the problem is also more block.
The source code below is an excerpt from Axios
Implementation of the underlying request
First let’s look at how requests are made inside Axios.
axios/lib/defaults.js
function getDefaultAdapter() {
var adapter;
if (typeofXMLHttpRequest ! = ='undefined') {
// For browsers use XHR adapter
adapter = require('./adapters/xhr');
} else if (typeofprocess ! = ='undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('./adapters/http');
}
return adapter;
}
var defaults = {
adapter: getDefaultAdapter()
...
}
module.exports = defaults;
Copy the code
The defaults file basically adds some default configuration to Axios, even if we don’t add any Accept, headers, timeout, etc., when we request it, it will help us add it by default, so that we can use it directly to simplify the cost.
The getDefaultAdapter function has compatible statements that use different request objects in the current environment. If the current environment typeof XMLHttpRequest! Typeof Process! == ‘undefined’; == ‘undefined’, since the process object is the built-in object that initiates the request in the Node environment, this means that axios will use different methods to initiate the request in the node environment. We are currently developing on the browser side. Let’s go to the./ Adapters/XHR file and see how the request is initiated on the browser side.
axios/lib/adapters/xhr.js
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var request = new XMLHttpRequest();
var fullPath = buildFullPath(config.baseURL, config.url);
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
request.timeout = config.timeout;
// Listen for ready state
request.onreadystatechange = function handleLoad() {
if(! request || request.readyState ! = =4) {
return;
}
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') = = =0)) {
return;
}
var response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config: config,
request: request
};
settle(resolve, reject, response);
request = null;
};
request.onabort = function handleAbort() {
if(! request) {return;
}
reject(createError('Request aborted', config, 'ECONNABORTED', request));
request = null;
};
request.onerror = function handleError() {
reject(createError('Network Error', config, null, request));
request = null;
};
request.ontimeout = function handleTimeout() {
var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded';
if (config.timeoutErrorMessage) {
timeoutErrorMessage = config.timeoutErrorMessage;
}
reject(createError(timeoutErrorMessage, config, 'ECONNABORTED',
request));
request = null;
};
// Handle progress if needed
if (typeof config.onDownloadProgress === 'function') {
request.addEventListener('progress', config.onDownloadProgress);
}
// Not all browsers support upload events
if (typeof config.onUploadProgress === 'function' && request.upload) {
request.upload.addEventListener('progress', config.onUploadProgress);
}
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if(! request) {return;
}
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
if(! requestData) { requestData =null;
}
// Send the requestrequest.send(requestData); }}Copy the code
I’ve removed some of the concrete implementations here, leaving only the mainline flow. The config argument passed by the function can be thought of as the sum of the values we passed and the defaults defaults arguments.
-
First, we see that the whole function body is wrapped in a Promise object and returns a Promise instance. This explains why we can use AXIos to make a successful request and then catch it. An object of type promise is returned from within it, which is much more asynchronous than the way we used to receive results using callbacks. Internally, resolve returns the correct result using two arguments of Promise,reject returns the cause of the error.
-
Moving on, the core code for making a request is new XMLHttpRequest(). Whether it’s axios today or jquery before us, the bottom line of how we request on the front end has not changed so far. Both take advantage of XMLHttpRequest’s ability to request a specific URL without refreshing the page to interact with the server. XMLHttpRequest
- Internal instance in XHR
request
A set of hook functions, such as onabort, onError, and onTimeout, reject, encapsulate and throw a request error. - The main ways to initiate a request are
request.open
It initializes the request with method and the URL after concatenating the parameters. thenrequest.send(requestData)
The request is issued with the body argument. - So let’s see
onreadystatechange
The hook function, which intercepts readyState and status values internally, listens for the request to return normally and calls settle(resolve internally) to return the wrapped response.
- Internal instance in XHR
-
We also see that the corresponding function is called internally via the upload and download progress hooks of the Request. If you want to explicitly see the progress bar when calling the interface, you can configure these two functions to implement this.
On the whole, the main help we finished the configuration inside the XHR combined will request a series of operations, the packaging, we just consider the parameters of the transfer, no longer need to consider how the interface request axios inside after the encapsulation simplifies the invocation logic and maintainability, this way of development can also be applied to the development of our actual work, Decouple core code from business to improve code reuse.
Interceptor implementation
Before we look at interceptors, let’s take a look at how we used them in the project.
./request/config.js
// Request interceptor
axios.interceptors.request.use(
config= > {
return config
},
err= > {
return err
}
)
// Response interceptor
axios.interceptors.response.use(
response= > {
return response
},
error= > {
return error
}
)
Copy the code
This object has two properties: Request and Response. These two properties correspond to the operations we want to do before and after the request. Call the use function to configure the two functions.
See the configuration, let’s look at the source code implementation: axios/lib/core/ axios.js
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
Copy the code
We see this. Interceptors in the Axios constructor. When we use an instance of Axios to get the interceptors object, we will look up to the Axios prototype to find it. Let’s take a look at what’s new InterceptorManager() and what it does when it calls its use function.
axios/lib/core/InterceptorManager.js
var utils = require('. /.. /utils');
function InterceptorManager() {
this.handlers = [];
}
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null; }}; InterceptorManager.prototype.forEach =function forEach(fn) {
utils.forEach(this.handlers, function forEachHandler(h) {
if(h ! = =null) { fn(h); }}); };module.exports = InterceptorManager;
Copy the code
The InterceptorManager prototype defines three methods and an array.
- The use function stores the two states of the functions passed in during configuration, namely depressing and Rejected, into the handlers in the form of objects. The order of push is successively added according to the order of invocation in configuration, so the order of request and response interceptors cannot be changed when we configure them.
- The eject function sets the specified element to null, removing the defined interceptor. This allows us to execute different interceptors based on the business that is not available.
- ForEach passes the interceptor to
fn(h)
Function, which we’ll use later.
After looking at the store, delete, traverse, and so on inside the interceptor, let’s look at how functions configured in the interceptor are called in Axios.
Take a look at the interceptor’s overall execution method, and then compare it with the implementation in the source code. We see that the request interceptor follows the first-in, first-in, first-in principle, and the response interceptor follows the first-in, first-in, first-in principle, and the whole process is a chain call process, interluding our call interfacedispatchRequest
Method, so as to achieve our configuration interception, interception of the response body such a logic.
axios/lib/core/Axios.js
Axios.prototype.request = function request(config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof config === 'string') {
config = arguments[1) | | {}; config.url =arguments[0];
} else {
config = config || {};
}
config = mergeConfig(this.defaults, config);
// Set config.method
if (config.method) {
config.method = config.method.toLowerCase();
} else if (this.defaults.method) {
config.method = this.defaults.method.toLowerCase();
} else {
config.method = 'get';
}
// Hook up interceptors middleware
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
Copy the code
MergeConfig merges the config configuration parameters we passed in according to the merge rules. We can see the merge of the this.defaults of the previous analysis and the merge of our custom config. This is why we can initiate requests without having to configure any parameters.
Axios uses arrays to make chain calls, inserting request interceptors in front of the chain and response interceptors in back of the chain using forEach methods on request and response, thus creating an overall chain structure.
The core idea here is to cleverly use promise’s chain invocation to achieve the effect of interceptor layer after layer of chain invocation. The fulfilled and Rejected methods in the chain are gradually added to promise.then() with the while statement, because the first promise object is a manual promise.resolve (config) which returns the configuration file. Therefore, the depressing function in the then function will be triggered. After the internal implementation of the function is completed, a Promise object will be returned again and assigned to the Promise. Then the repeated operation will complete the execution of all interceptors and finally return to us a processed Promise. All we have to do is accept the promise that comes back and we get the result we want.
conclusion
Entire chapter to this end, we from the axios configuration used to analyze the underlying implementation of the principle idea every time we launched the request what plug-ins are dry, we can learn by reading the source code to plug-in the packaging design and implementation of ideas, help us to improve their ability, also helped us to plug-in a deeper understanding, When the plug-in itself does not meet our needs, we can also extend it ourselves. In the front end technology innovation today, we improve their ability to use a variety of technologies at the same time should also sink down to see the source code, after all, when the interview to talk about the source code is still quite a plus [dog head].
Secondly, the axios.cancel mechanism involved in the configuration section of this article will not be analyzed here, you can directly go to Github to see how to implement it.