我们都知道,发起网络请求这个任务,是一个异步任务。
大家可以看看以下代码中,网络请求中携带的参数是什么:
const total = 500;
const params = {
optionsA: "a",
optionsB: "b",
optionsC: "c",
page:{
currentPage: 1,
pageSize: 20,
}
};
const maxPage = Math.ceil(total / params.page.currentPage)
while(params.page.currentPage <= maxPage){
// 发起网络请求
axios.post('https://xxxxx.xxx.com/xxxx', params);
// 页码增加
params.page.currentPage++;
}
上述代码的本意是为了获取当前参数下所有的数据,所以会从第一页开始获取数据。但得到的输出结果却是下面的这个
// 这里模仿的是在浏览器按下F12进入控制台中网络请求中的请求体
// 第一次请求
data:{
optionsA: "a",
optionsB: "b",
optionsC: "c",
page:{
currentPage: 26,
pageSize: 20,
}
}
// 第二次请求
data:{
optionsA: "a",
optionsB: "b",
optionsC: "c",
page:{
currentPage: 26,
pageSize: 20,
}
}
// 第三次请求
data:{
optionsA: "a",
optionsB: "b",
optionsC: "c",
page:{
currentPage: 26,
pageSize: 20,
}
}
......
// 一共25次请求中的currentPage都是一样的
因为超出边界的缘故,所以每一次返回回来的数据都是null。
于是这里我就开始好奇了,为什么每次请求发出的currentPage都是26呢,为什么不是从1递增到25(对应上述我定义的maxSize)
我当然知道网络请求是异步的,但在过往我的认知中,这个异步是指其请求过程以及其请求结果的异步,也就是我们发出请求是同步的,而在请求回来以及后续处理的过程是属于异步的。
如果按这个思路走,那么就应该是从第1页递增到第25页才对啊。
我猜测一共有两种可能
- axios将请求的发送放到了异步当中
- xhrHttpRequest本身就是异步发送请求的
为了验证我的猜想,我就去翻了翻axios的源码
相关路径在node_modules/axios/lib
首先,我们顺着axios.[methods]的方向往下找,很快就找到了相关的源码,源码部分有兴趣的可以看看,懒得看得看我的文字也够了
// node_modules/axios/lib/core/Axios.js
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url,
data: data
}));
};
});
utils是一个工具库,有兴趣的可以去看看它的中文文档,utils中文文档|utils js中文教程|解析 | npm中文文档 (npmdoc.org)
上述代码的forEach和Array.prototype.map有点相似,return的值会成为新数组中的对应元素,当然这里没用到,这里是起到了遍历的操作。
顺着往下找,我们找到了this.request的定义
// node_modules/axios/lib/core/Axios.js
/**
* Dispatch a request
*
* @param {Object} config The config specific for this request (merged with this.defaults)
*/
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 = utils.merge({
url: arguments[0]
}, arguments[1]);
}
config = utils.merge(defaults, {method: 'get'}, this.defaults, config);
config.method = config.method.toLowerCase();
// 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;
};
我们重点看21行及其之后的代码片段
可以看到,在21行定义了一个chain变量,这是作为一个类似于钩子函数队列的存在,也就是存放我们的请求拦截器和响应拦截器的地方,24行就是往队列首部添加请求拦截器,28行就是往队列尾部添加响应拦截器
其实从这里,就已经可以看出本篇文章所需要寻求的答案
最后我们在33行可以看到,从chain队列中取任务的操作通过promise的then方法放入到了微任务队列中,并且通过then链式调用,最后调用到我们的dispatchRequest方法(发送请求的方法,由原生xhrHttpRequest或者http模块封装)
所以通过以上研究可以明白,axios中的异步,这是真的从开始到结束,都是在异步完成的
,再回到一开始的问题,如果想要并发多个请求,可以更改代码为以下内容
const total = 500;
const page = 1;
const pageSize = 20;
const maxPage = Math.ceil(total / pageSize)
while(page <= maxPage){
// 定义参数
const params = {
optionsA: "a",
optionsB: "b",
optionsC: "c",
page:{
currentPage: page,
pageSize: pageSize,
}
};
// 发起网络请求
axios.post('https://xxxxx.xxx.com/xxxx', params);
// 页码增加
page++;
}
好了我要加班去了,拜拜咯,喜欢的话给我点个赞,收藏,评论一下都好,让我开心开心谢谢你们!!
如果有不对的,欢迎大佬们多指导一下!!!
原文链接:https://juejin.cn/post/7311728260135731219 作者:笑心