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內核

 

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