環境
測試環境: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也可以明顯看出,
- 所有請求的開始時間點是一樣的
- 但是後續請求都有等待時間(灰色),都是上一個請求開始到結束時間
- 每個請求的真正時間(綠色)幾乎一樣,但總時長越往後請求越慢,都是上一個請求結束纔開始下一個
- 以上看出完全是串行請求,並沒有達到我們的預期
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內核)連接數有關,還有些問題,比如如何修改連接數等這裏不再深究。一些參考資料如下:
electron中使用got未發現此問題,這個庫是node環境庫,可能不經過chrome內核