在開發中,咱們可能會遇到一些對異步請求數作併發量限制的場景,好比說微信小程序的request併發最多爲5個,又或者咱們須要作一些批量處理的工做,但是咱們又不想同時對服務器發出太多請求(可能會對服務器形成比較大的壓力)。這個時候咱們就能夠對請求併發數進行限制,而且使用排隊機制讓請求有序的發送出去。javascript
那麼,接下來咱們就來說一下如何實現一個通用的能對請求併發數進行限制的RequestDecorator。咱們先來介紹一下它的功能:java
分析完功能後,接下來咱們就來實現這個東西:ios
具體代碼以下,每一步我基本都作了註釋,相信你們能看懂。git
const pify = require('pify'); class RequestDecorator { constructor ({ maxLimit = 5, requestApi, needChange2Promise, }) { // 最大併發量 this.maxLimit = maxLimit; // 請求隊列,若當前請求併發量已經超過maxLimit,則將該請求加入到請求隊列中 this.requestQueue = []; // 當前併發量數目 this.currentConcurrent = 0; // 使用者定義的請求api,若用戶傳入needChange2Promise爲true,則將用戶的callback類api使用pify這個庫將其轉化爲promise類的。 this.requestApi = needChange2Promise ? pify(requestApi) : requestApi; } // 發起請求api async request(...args) { // 若當前請求數併發量超過最大併發量限制,則將其阻斷在這裏。 // startBlocking會返回一個promise,並將該promise的resolve函數放在this.requestQueue隊列裏。這樣的話,除非這個promise被resolve,不然不會繼續向下執行。 // 當以前發出的請求結果回來/請求失敗的時候,則將當前併發量-1,而且調用this.next函數執行隊列中的請求 // 當調用next函數的時候,會從this.requestQueue隊列裏取出隊首的resolve函數而且執行。這樣,對應的請求則能夠繼續向下執行。 if (this.currentConcurrent >= this.maxLimit) { await this.startBlocking(); } try { this.currentConcurrent++; const result = await this.requestApi(...args); return Promise.resolve(result); } catch (err) { return Promise.reject(err); } finally { console.log('當前併發數:', this.currentConcurrent); this.currentConcurrent--; this.next(); } } // 新建一個promise,而且將該reolsve函數放入到requestQueue隊列裏。 // 當調用next函數的時候,會從隊列裏取出一個resolve函數並執行。 startBlocking() { let _resolve; let promise2 = new Promise((resolve, reject) => _resolve = resolve); this.requestQueue.push(_resolve); return promise2; } // 從請求隊列裏取出隊首的resolve並執行。 next() { if (this.requestQueue.length <= 0) return; const _resolve = this.requestQueue.shift(); _resolve(); } } module.exports = RequestDecorator;
樣例代碼以下:github
const RequestDecorator = require('../src/index.js') // 一個callback類型的請求api function delay(num, time, cb) { setTimeout(() => { cb(null, num); }, time); } // 經過maxLimit設置併發量限制,needChange2Promise將callback類型的請求api轉化爲promise類型的。 const requestInstance = new RequestDecorator({ maxLimit: 5, requestApi: delay, needChange2Promise: true, }); let promises = []; for (let i = 0; i < 30; i++) { // 接下來你就能夠像原來使用你的api那樣使用它,參數和原來的是同樣的 promises.push(requestInstance.request(i, Math.random() * 3000).then(result => console.log('result', result), error => console.log(error))); } async function test() { await Promise.all(promises); } test();
這樣,一個能對請求併發數作限制的通用RequestDecorator就已經實現了。固然,這裏還有不少能夠繼續增長的功能點,好比ajax
優勢:axios
以上,就是本篇的所有內容。github倉庫地址點擊這裏。歡迎你們點贊或者star下。若是你們有興趣的話,也能夠一塊兒來完善這個東西。這個項目還不成熟,可能還會有bug,歡迎你們在github上提issue幫助我完善它。若是以爲有幫助的話,麻煩點個贊哦,謝謝。小程序
本文地址在->本人博客地址, 歡迎給個 start 或 follow微信小程序