preface
In daily development, when we use AXIos to pass parameters, we often get confused about where the parameters are passed because AXIos does merge compatibility with the parameters we pass. Now let’s look at the use of axios parameters from the source level.
Three ways to use Axios
- axios.request(config)
- axios.get(url,config)/axios.post(url,data,config)
- axios(config)
Axios returns a method, iterates through all methods on axios. Prototype, and assigns values to axios, so axios can support multiple calls.
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
var instance = bind(Axios.prototype.request, context);
// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context);
// Copy context to instance
utils.extend(instance, context);
return instance;
}
Copy the code
Parameter merge for Axios
Axios receives only a config object that contains the url, method, params, body, headers and other parameters that are commonly used. It can be passed separately because the parameters are merged internally.
utils.forEach(['delete'.'get'.'head'.'options'].function forEachMethodNoData(method) {
Axios.prototype[method] = function(url, config) {
// merge into a config object
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: (config || {}).data
}));
};
});
utils.forEach(['post'.'put'.'patch'].function forEachMethodWithData(method) {
Axios.prototype[method] = function(url, data, config) {
// merge into a config object
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: data
}));
};
});
Copy the code
Params and data arguments to Axios
The params parameter of AXIos is simply processed, concatenated to the URL, and then requested the interface. The data parameter is directly used as the body, and passed to the background interface through xhr.send(data). The source code is as follows:
- Params parameter processing
var request = new XMLHttpRequest();
var fullPath = buildFullPath(config.baseURL, config.url);
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params), true);
// ...
function buildURL(url, params) {
var serializedParams;
var parts = [];
utils.forEach(params, function serialize(val, key) {
if (val === null || typeof val === 'undefined') return;
// Handle the array parameters
if (utils.isArray(val)) {
key = key + '[]';
} else {
val = [val];
}
// Handle date arguments and ordinary objects
utils.forEach(val, function parseValue(v) {
if (utils.isDate(v)) {
v = v.toISOString();
} else if (utils.isObject(v)) {
v = JSON.stringify(v);
}
parts.push(encode(key) + '=' + encode(v));
});
});
// Concatenate parameters to the URL
serializedParams = parts.join('&');
if (serializedParams) {
var hashmarkIndex = url.indexOf(The '#');
if(hashmarkIndex ! = = -1) {
url = url.slice(0, hashmarkIndex);
}
url += (url.indexOf('? ') = = = -1 ? '? ' : '&') + serializedParams;
}
return url;
};
Copy the code
- The data parameter
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var requestData = config.data;
var request = new XMLHttpRequest();
// ...request.send(requestData); })}Copy the code
Headers default argument for Axios
Headers of the parameters of axios axios support according to your different request method, set up different default parameters, via axios.defaults.headers.com mon = {XXX: “XXX “} Settings,axios arguments support axios.defaults Settings, but have lower precedence than the passed config arguments
defaults.headers = {
common: {
'Accept': 'application/json, text/plain, */*'}}; utils.forEach(['delete'.'get'.'head'].function forEachMethodNoData(method) {
defaults.headers[method] = {};
});
utils.forEach(['post'.'put'.'patch'].function forEachMethodWithData(method) {
defaults.headers[method] = utils.merge({
'Content-Type': 'application/x-www-form-urlencoded'
});
});
Copy the code
Axios interceptor and adapter
The basic use
/ / the interceptor
axios.interceptors.request.use(config= > {
config.headers = {
'Content-Type': 'application/x-www-form-urlencoded' // Configure the request header
}
return config;
}, error= >{});/ / adapter
axios.interceptors.response.use(response= > {
response.data = "XXX"
return response
}, error= >{})Copy the code
Implementation idea:
- The use method pushes the incoming callback into the interceptor and adapter arrays, respectively
- Create an array of ajax methods preceded by the unshift interceptor callback and followed by the push adapter callback
- The order of calls is guaranteed through the chain calls of promise.then
- Thus, the corresponding parameters are invoked before each request is sent (interceptor) and after each request is successful (adapter).
The core source code is as follows:
// The adapter and interceptor use the same constructor to implement a use method
function InterceptorManager() {
this.handlers = [];
}
InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
// The instance is mounted on axios.interceptors
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(), / / the interceptor
response: new InterceptorManager() / / adapter
};
}
Axios.prototype.request = function request(config) {
var requestInterceptorChain = [];
// The interceptor's function collects the array
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// The adapter's function collects the array
var responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
var promise;
// Send ajax requests in the middle
var chain = [dispatchRequest, undefined];
// Interceptor functions come before Ajax
Array.prototype.unshift.apply(chain, requestInterceptorChain);
// The adapter functions come after Ajax
chain.concat(responseInterceptorChain);
// We pass config as the function argument, and response as the function argument after dispatchRequest
promise = Promise.resolve(config);
// concatenate all functions with promise.then
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
Copy the code
Axios cancel request
Two ways of use
- Pass in a cancelToken argument whose value is an instance of the cancelToken function
- Save the resolve function and execute it if necessary
/ / way
const source = axios.CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
});
// Cancel the request
source.cancel();
2 / / way
let cancel;
axios.get('/user/12345', {
cancelToken: new axios.CancelToken(function executor(c) { cancel = c; })});// Cancel the request
cancel();
Copy the code
The source code to achieve
The core idea is that promise+xhr.abort is implemented
- Create an instance of CancelToken, passing in a callback function
- A Promise is mounted on the instance, and the promise’s resolve method is passed as an argument
- When sending an XHR request, register promise.then to interrupt the request
- Execute promise’s resolve method outside, breaking the request
function CancelToken(executor) {
var resolvePromise;
// Create a Promise object
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
// Pass promise's resolve method when the constructor executes
executor(function cancel() {
resolvePromise();
});
}
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var request = new XMLHttpRequest();
request.open(config.method.toUpperCase(), true);
// Native JS onabort method
request.onabort = function handleAbort() {
reject();
};
// ...
if (config.cancelToken) {
// The promise created here is waiting to be executed
config.cancelToken.promise.then(function onCanceled(cancel) {
request.abort();
reject(cancel);
});
}
request.send(requestData);
});
};
Copy the code
Upload and download progress monitoring method
The basic use
- Use the same method as passing headers or other parameters to config.
axios({
onUploadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},
// 'onDownloadProgress' allows progress events to be processed for downloads
onDownloadProgress: function (progressEvent) {
// Handling of native progress events}}})Copy the code
The source code to achieve
Here the source code implementation is very simple, directly call XHR two native corresponding methods
function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var request = new XMLHttpRequest();
request.open(config.method.toUpperCase(), url, true);
// Handle progress if needed download progress
if (typeof config.onDownloadProgress === 'function') {
request.addEventListener('progress', config.onDownloadProgress);
}
// Not all Browsers support Upload events Upload progress
if (typeof config.onUploadProgress === 'function' && request.upload) {
request.upload.addEventListener('progress', config.onUploadProgress);
}
// Send the request
request.send(requestData);
});
};
Copy the code
The last
The implementation of AXIos, from the source point of view, is not very difficult, the source code posted in the article is some deleted, interested friends, you can refer to the source code to see the specific implementation, using Axios in work more smooth, finally, if the article is helpful to you, don’t forget to like oh ~