JS明明写的请求是并行,为何仍然串行请求?

环境

测试环境:electron + vue + axios

需求

想要做并行请求(比如爬虫)需要尽量快的请求页面。

假如一次发出请求到返回所需时间为100ms:

方案1(串行):请求一次接口等待返回处理结果后继续下一次请求。这样会受制于请求的速度,假如请求100次那么需要总时间为100ms * 100 = 10000ms

方案2(并行):利用Promise,同时发起多个请求,但不等待每个请求结束。而是Promise.all等待其全部结束再进行处理。假如请求100次那么需要总时间为100ms * 1= 100ms

可以看出速度有极大的提升,理论上(实际需要看机器配置和网络带宽情况)无论多少请求都只需要100ms。

 

并行实现

我们的需求就是方案2的并行实现。所以如下实现:

            async t () {
        const time1 = new Date().getTime() / 1000
        const task = []
        for (let i=0; i < 100; i++){
            task.push(this.t1())  // 发起请求
        }
        await Promise.all(task)  // 等待所有请求结束
        // await this.$http.all(task)  // 与Promise一样
        const time2 = new Date().getTime() / 1000
        console.log('time:', time2 - time1)
      },
      async t1 () {
        const res = await this.$http({
          method: 'get',
          baseURL: this.url,
          url: LOGIN_PATH,  // 关键:正常url
        })
      }

结果仍然是串行?

查看console程序的time输出很高,是所有请求时间累加的时间。

查看network,从time和waterfall也可以明显看出,

  1. 所有请求的开始时间点是一样的
  2. 但是后续请求都有等待时间(灰色),都是上一个请求开始到结束时间
  3. 每个请求的真正时间(绿色)几乎一样,但总时长越往后请求越慢,都是上一个请求结束才开始下一个
  4. 以上看出完全是串行请求,并没有达到我们的预期

network图如下:

问题在哪?

我们都知道浏览器中请求都应该是并行的,html中加载网络文件和请求也通常都是并行的。

观察发现这里所有经过url都是一致的,而一般网页开发时很少出现一个页面请求多次同样的url的,所以这里很可疑。

经过尝试,将每次url都改为不完全一样,确实解决了此问题。(怀疑是浏览器的问题,非axios问题。而之后使用node版的got未发现此问题)

 

修改代码,请求的url增加随机参数使其完整url每次都发生变化,修改部分代码如下:

      async t1 () {
        const res = await this.$http({
          method: 'get',
          baseURL: this.url,
          // url: LOGIN_PATH,  // 关键:正常url
          url: LOGIN_PATH + `?v=${Math.random()}`,  // 关键:增加随机参数
        })
      }

查看console的程序输出时间已经为几乎只有一个请求的时间。

查看network所有请求也都同时开始,也几乎(网络因素影响,不可能每次时间都一样)同时结束,总耗时只有200ms多

查询资料及测试发现,“chrome + jquery”并行请求看起来是6个一块,与资料所述chrome浏览器http最大连接数为6一致,基本可以判定这次主要问题在于浏览器或者electron(实际扔使用的chrome内核)连接数有关,还有些问题,比如如何修改连接数等这里不再深究。一些参考资料如下:

  1. 浏览器同域名请求的最大并发数限制
  2. 浏览器HTTP请求并发数和TCP连接的关系

electron中使用got未发现此问题,这个库是node环境库,可能不经过chrome内核

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章