axios调用办法
- axios.create(config)
- axios.method(url, config)
完成
function createInstance(defaultConfig) {
const context = new Axios(defaultConfig)
const instance = Axios.prototype.request.bind(context)
utils.extend(instance, Axios.prototype, context)
utils.extend(instance, context, null)
instance.create = function create(config) {
return createInstance(mergeConfig(default, config))
}
return instance
}
const axios = createInstance(defaultConfig)
defaults中有什么
const defaults = {
...,
headers: {
common: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': undefined
}
}
}
utils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch'], (method) => {
defaults.headers[method] = {};
});
- 由此可见,defaults会为headers中增加common以及其他恳求办法为特点名,值为对象
Axios类
class Axios {
constructor(instanceConfig) {
this.defaults = instanceConfig
this.interceptors = {
request: new InterceptorManager()
response: new InterceptorManager(),
}
}
request(configOrUrl, config) {
if (typeof configOrUrl === 'string') {
config = config || {}
config.url = configOrUrl
} else {
config = configOrUrl || {}
}
config = mergeConfig(this.defaults, config)
config.method = (config.method || thhis.default.method || 'get').toLowerCase()
const { headers } = config;
let contextHeaders = headers && utils.merge(
headers.common,
headers[config.method]
);
headers && utils.forEach(
['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
(method) => {
delete headers[method];
}
);
config.headers = AxiosHeaders.concat(contextHeaders, headers);
const requestInterceptorChain = [];
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
...
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
const responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
const chain = [dispatchRequest.bind(this), undefined];
chain.unshift.apply(chain, requestInterceptorChain);
chain.push.apply(chain, responseInterceptorChain);
len = chain.length;
promise = Promise.resolve(config);
while (i < len) {
promise = promise.then(chain[i++], chain[i++]);
}
return promise;
}
}
- 这当地主要是处理了config、URL以及header,然后将恳求拦截器逆序参加数组,呼应拦截器次序参加数组,当一个恳求发送出去的时分为 恳求拦截器逆序履行 -> 发送恳求 -> 呼应拦截器次序履行
拦截器
class InterceptorManager {
constructor() {
this.handlers = []
}
use(fulfilled, rejected, options) {
this.handlers.push({
fulfilled,
rejected,
synchronous: options ? options.synchronous : false,
runWhen: options ? options.runWhen : null
})
return this.handlers.length - 1
}
eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
}
clear() {
if (this.handlers) {
this.handlers = [];
}
}
}
- 拦截器办理便是一个数组,使用use寄存成功和失利对应的回调,会回来一个id也便是当时寄存的下标,用于撤销寄存
发送恳求的dispatchRequest
function throwIfCancellationRequested(config) {
if (config.cancelToken) {
config.cancelToken.throwIfRequested();
}
if (config.signal && config.signal.aborted) {
throw new CanceledError(null, config);
}
}
function dispatchRequest(config) {
throwIfCancellationRequested(config);
const adapter = adapters.getAdapter(config.adapter || defaults.adapter);
return adapter(config).then(response => {
throwIfCancellationRequested(config);
...
return response
}, reason => {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
}
return Promise.reject(reason)
})
}
真正发送恳求的adapter
- Axios 是一个基于promise 网络恳求库,作用于node和阅读器中。 在服务端它使用原生 node.js
http
模块, 而在客户端 (阅读端) 则使用 XMLHttpRequests
。
const knownAdapters = {
http: httpAdapter,
xhr: xhrAdapter
}
function dispatchXhrRequest(config) {
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest();
const fullPath = buildFullPath(config.baseURL, config.url);
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
request.timeout = config.timeout;
request.onabort = function handleAbort() {
if (!request) {
return;
}
reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));
request = null;
};
request.onerror = function handleError() {
reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request));
request = null;
};
request.ontimeout = function handleTimeout() {
let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
const transitional = config.transitional || transitionalDefaults;
if (config.timeoutErrorMessage) {
timeoutErrorMessage = config.timeoutErrorMessage;
}
reject(new AxiosError(
timeoutErrorMessage,
transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,
config,
request));
request = null;
};
let onCanceled;
if (config.cancelToken || config.signal) {
onCanceled = cancel => {
if (!request) {
return;
}
reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel);
request.abort();
request = null;
};
config.cancelToken && config.cancelToken.subscribe(onCanceled);
if (config.signal) {
config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
}
}
function onloadend() {
if (!request) {
return;
}
const responseHeaders = AxiosHeaders.from(
'getAllResponseHeaders' in request && request.getAllResponseHeaders()
);
const responseData = !responseType || responseType === 'text' || responseType === 'json' ?
request.responseText : request.response;
const response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config,
request
};
settle(function _resolve(value) {
resolve(value);
done();
}, function _reject(err) {
reject(err);
done();
}, response);
request = null;
}
function done() {
if (config.cancelToken) {
config.cancelToken.unsubscribe(onCanceled);
}
if (config.signal) {
config.signal.removeEventListener('abort', onCanceled);
}
}
request.onloadend = onloadend;
request.send(requestData || null);
})
}
- 总的来说便是根据环境判别能够用node的http还是阅读器的xhr,其间对config传入的cancelToken调用其订阅办法,订阅能够撤销promise的办法,当撤销的时分会调用request.abort()然后reject掉promise,即便发送了网络恳求,在后续adapter根据promise对应的resolve或reject状况会进行判别是否撤销过,撤销过则丢出过错。
撤销恳求的CancelToken
class CancelToken {
static source() {
let cancel
const token = new CancelToken(c => {
cancel = c
})
return {
token,
cancel
}
}
constructor(executor) {
const token = this
let resolvePromise;
executor(function cancel(message, config, request) {
if (token.reason) {
return
}
token.reason = new CanceledError(message, config, request);
resolvePromise(token.reason)
})
token.promise = new Promise((resolve, reject) => {
resolvePromise = resolve
})
this.promise.then(cancel => {
if (!token._listeners) return;
let i = token._listeners.length;
while (i-- > 0) {
token._listeners[i](cancel);
}
token._listeners = null;
});
}
subscribe(listener) {
if (this.reason) {
listener(this.reason);
return;
}
if (this._listeners) {
this._listeners.push(listener);
} else {
this._listeners = [listener];
}
}
}
- 总而言之,撤销函数是通过向外传递一个变量cancel,该变量又被赋值为一个函数,该函数被调用就会给当时this(也便是token)寄存一个reason标志现已调用过,履行promise的resolve办法,然后履行一切订阅的函数,包含了adapter中存储的cancel(也便是会履行request.abort导致request地点的promise状况变为reject)