使用 Promise 實現任務隊列發送請求,實現最大請求數目限制
核心
- 設置最大請求數量,當前請求數量,待執行隊列
- 調用時,創建一個新任務,然後判斷是否達到最大請求數量,若達到則將任務追加到待執行隊列,否則,則直接執行該任務。並返回Promise
- 創建任務時,需要返回一個函數,當該任務開始執行則當前數量加一。當任務執行完畢時使用finally,當前數量減一,並從待執行隊列中取出新任務執行
實現
class limitPromise{ constructor(max){ this.max = max; this._count = 0; this._pendingTaskQueue = []; } /** * 調用器,將異步任務函數和它的參數傳入 * @param caller 異步任務函數,返回Promise的函數 * @param args 異步任務函數的參數列表 * @returns {Promise<unknown>} 返回一個新的Promise */ call = (caller, ...arg) => { return new Promise((resolve, reject) => { let task = this._createTask(caller, arg, resolve, reject); if(this._count >= this.max) { this._pendingTaskQueue.push(); }else{ task(); } }); } /** * 創建一個任務 * @param caller 實際執行的函數 * @param args 執行函數的參數 * @param resolve * @param reject * @returns {Function} 返回一個任務函數 * @private */ _createTask = (caller, arg, resolve, reject)=> { return () => { // 當前請求數量加一 this._count++; // 實際上是在這裡調用了異步任務,並將異步任務的返回(resolve和reject)拋給了上層 caller(...arg) .then(resolve) .catch(reject) .finally(() => { // 任務隊列的消費區,利用Promise的finally方法,在異步任務結束後,取出下一個任務執行 this._count--; if(this._pendingTaskQueue.length){ let task = this._pendingTaskQueue.shift(); task(); } }) } } }
使用
假設我們有一個網絡請求模塊,叫request.js,包含get和post方法,一般情況下,是這樣使用的
const request = require('./request') request.get('//www.baidu.com') .then((res) => { // 處理返回結果 }) .catch(err => { // 處理異常情況 })
現在我們要把它改造成受限制的網絡請求,假設請求上限設為10個,並起名叫limitRequest.js。實現如下:
const LimitPromise = require('limit-promise') const request = require('./request') // 請求上限 const MAX = 10 // 核心控制器 const limitP = new LimitPromise(MAX) // 利用核心控制器包裝request中的函數 function get (url, params) { return limitP.call(request.get, url, params) } function post (url, params) { return limitP.call(request.post, url, params) } // 導出 module.exports = {get, post}
這裡就完成受限請求模塊的構建了,是不是很簡單,而且調用接口完全沒變,只需要引入limitRequest.js替代原先的即可。
參考自