关于使用axios发起网络请求的异步问题

我们都知道,发起网络请求这个任务,是一个异步任务。

大家可以看看以下代码中,网络请求中携带的参数是什么:

js 复制代码
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++;
}

上述代码的本意是为了获取当前参数下所有的数据,所以会从第一页开始获取数据。但得到的输出结果却是下面的这个

js 复制代码
// 这里模仿的是在浏览器按下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页才对啊。

我猜测一共有两种可能

  1. axios将请求的发送放到了异步当中
  2. xhrHttpRequest本身就是异步发送请求的

为了验证我的猜想,我就去翻了翻axios的源码

相关路径在node_modules/axios/lib

首先,我们顺着axios.[methods]的方向往下找,很快就找到了相关的源码,源码部分有兴趣的可以看看,懒得看得看我的文字也够了

js 复制代码
// 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的定义

js 复制代码
// 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中的异步,这是真的从开始到结束,都是在异步完成的,再回到一开始的问题,如果想要并发多个请求,可以更改代码为以下内容

js 复制代码
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++;
}

好了我要加班去了,拜拜咯,喜欢的话给我点个赞,收藏,评论一下都好,让我开心开心谢谢你们!!

如果有不对的,欢迎大佬们多指导一下!!!

相关推荐
walking9573 分钟前
重新学习前端之设计模式与架构
前端·javascript·面试
walking9576 分钟前
重新学习前端之TypeScript
前端·javascript·面试
walking9576 分钟前
重新学习前端之Linux
前端·vue.js·面试
walking9577 分钟前
重新学习前端之CSS
前端·vue.js·面试
walking9577 分钟前
重新学习前端之Git
前端·vue.js·面试
walking9577 分钟前
重新学习前端之小程序
前端
魔术师Grace9 分钟前
AI让我退化成原始人了
前端·程序员
铁皮饭盒10 分钟前
今天你会学到这些关键词
前端·后端
李剑一12 分钟前
耗时 2 小时!我复刻了全网超火的通透 3D 水晶球动效,Vue3+Three.js 做出高级视觉特效
前端·three.js
oil欧哟18 分钟前
🤔 很长时间没写文章了,分享一下最近的一些思考
前端·后端