持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情aaaaaa
前言
终于要把坑填完了,axios的主要源码大体就结束了,之后会在已经写好的文章上面更新内容。axios源码的体量虽然不是很大,单包含了大部分的框架所用到的东西,花了好几天时间,断断续续的看玩后,理清了即便思路,感觉真的收获很大。在面试之前再拿出来复习复习
dispatchRequest
dispatchRequest.js
dispatchRequest中主要是对 配置data 和 返回的data的处理,发送请求时在 adapter 里面进一步划分的,
值得注意的内容是 config.transformRequest 中一系列函数 对data content-type的处理
adapter
在 defaults/index.js中我们可以找到 adapter的内容
我们顺着这个线索一步步往下
同样在 defaults/index.js 中
这里就是通过两个if语句来判断当前的环境是 浏览器环境还是node环境 。通常都是使用 xhr 在浏览器端发送请求
adapters/index.js
最后让我们进入到 xhr 的请求中看一看具体的发送请求过程
xhr.js
这里是我们真正发起请求的地方
export default function xhrAdapter(config) {
// 请求返回一个promise对象
return new Promise(function dispatchXhrRequest(resolve, reject) {
// 在这里获取config中的data内容,配置requestHeaders,responseType等等
let requestData = config.data;
const requestHeaders = AxiosHeaders.from(config.headers).normalize();
const responseType = config.responseType;
let onCanceled;
function done() {
if (config.cancelToken) {
config.cancelToken.unsubscribe(onCanceled);
}
if (config.signal) {
config.signal.removeEventListener('abort', onCanceled);
}
}
if (utils.isFormData(requestData) && platform.isStandardBrowserEnv) {
requestHeaders.setContentType(false); // Let the browser set it
}
// 在这里我们就嫩见到我们所熟知的 ajax 请求的部分 new XMLHttpRequest
let request = new XMLHttpRequest();
// HTTP basic authentication
if (config.auth) {
const username = config.auth.username || '';
const password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';
requestHeaders.set('Authorization', 'Basic ' + btoa(username + ':' + password));
}
// 构建一个完整的路径
const fullPath = buildFullPath(config.baseURL, config.url);
// 发起初始化一个ajax请求,method url、参数、序列化函数
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
// Set the request timeout in MS
// 设置请求超时
request.timeout = config.timeout;
// 注意 promise的 resolve() 和 reject() 函数是在这里面执行的
function onloadend() {
//
if (!request) {
return;
}
// Prepare the response
// 准备 请求返回的结果 response
const responseHeaders = AxiosHeaders.from(
'getAllResponseHeaders' in request && request.getAllResponseHeaders()
);
const responseData = !responseType || responseType === 'text' || responseType === 'json' ?
request.responseText : request.response; //在这里判断 responseType 是什么值,然后获取对应的 请求结果
// 把结果进行封装一下
const response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config,
request
};
// 当readystatus == 4时,才会执行
// settle的参数为 成功回调,失败回调,response
settle(function _resolve(value) {
resolve(value);
done();
}, function _reject(err) {
reject(err);
done();
}, response);
// Clean up request
request = null;
}
//
if ('onloadend' in request) {
// ajax 的 onloadend 会在请求结束时触发
request.onloadend = onloadend;
} else {
// Listen for ready state to emulate onloadend
// 如果没有定义 ajax的onloadend的话,就在下面 监听 onreadystatechange,status 如果结果成功(状态时4)的话,就异步执行onloadend
request.onreadystatechange = function handleLoad() {
if (!request || request.readyState !== 4) {
return;
}
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
return;
}
// readystate handler is calling before onerror or ontimeout handlers,
// so we should call onloadend on the next 'tick'
setTimeout(onloadend);
};
}
// 下面都是定义在不同状态下的 ajax 的处理情况 例如 调用 ajax 的onabort,onerror,ontimeout等等
// Handle browser request cancellation (as opposed to a manual cancellation)
request.onabort = function handleAbort() {
if (!request) {
return;
}
reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));
// Clean up request
request = null;
};
// Handle low level network errors
//设置出错时的情况
request.onerror = function handleError() {
// Real errors are hidden from us by the browser
// onerror should only fire if it's a network error
reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request));
// Clean up request
request = null;
};
// Handle timeout
// 设置超时的情况
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));
// Clean up request
request = null;
};
//这里把 xsrf 的一部分内容删掉了
// Send the request
// 在最后,发起请求,
request.send(requestData || null);
});
我对里面重要代码的部分进行了一系列的解释,大概照着思路就能看明白。
- new XMLHttpRequest,
- request.open()
- request.timeout
- request.ontimeout()
- onloadend函数中对应的 onreadystatechange 的改变时
- 还有最后的send()的发起
- 这些都是ajax的关键,也是axios在浏览器端的底层请求。要好好弄明白了
其中设置了很多 ajax 的处理函数,最主要的内容是 onloadend函数 的定义。还有ajax请求发起的几个重要过程。在上面的代码中,已经把需要注意的地方用注释说明了,(建议放到编译器中方便看)
后续还有很多内容需要补充,等待细节更新!