需求:
- 設置最大請求數量,當前請求數量,待執行隊列
- 調用時,創建一個新任務,然后判斷是否達到最大請求數量,若達到則將任務追加到待執行隊列,否則,則直接執行該任務。並返回Promise
- 創建任務時,需要返回一個函數,當該任務開始執行則當前數量加一。當任務執行完畢時使用finally,當前數量減一,並從待執行隊列中取出新任務執行
實現:
/* eslint-disable */ export class LimitPromise { constructor (max) { // 異步任務“並發”上限 this._max = max // 當前正在執行的任務數量 this._count = 0 // 等待執行的任務隊列 this._taskQueue = [] } /** * 調用器,將異步任務函數和它的參數傳入 * @param caller 異步任務函數,它必須是async函數或者返回Promise的函數 * @param args 異步任務函數的參數列表 * @returns {Promise<unknown>} 返回一個新的Promise */ call (caller, ...args) { return new Promise((resolve, reject) => { const task = this._createTask(caller, args, resolve, reject) if (this._count >= this._max) { // console.log('count >= max, push a task to queue') this._taskQueue.push(task) } else { task() } }) } /** * 創建一個任務 * @param caller 實際執行的函數 * @param args 執行函數的參數 * @param resolve * @param reject * @returns {Function} 返回一個任務函數 * @private */ _createTask (caller, args, resolve, reject) { return () => { // 實際上是在這里調用了異步任務,並將異步任務的返回(resolve和reject)拋給了上層 caller(...args) .then(resolve) .catch(reject) .finally(() => { // 任務隊列的消費區,利用Promise的finally方法,在異步任務結束后,取出下一個任務執行 this._count-- if (this._taskQueue.length) { // console.log('a task run over, pop a task to run') let task = this._taskQueue.shift() task() } else { // console.log('task count = ', count) } }) this._count++ // console.log('task run , task count = ', count) } } }
使用:
假設我們有一個請求方法this.$http.post方法,一般情況下,是這樣使用的
function requestDemo(){ this.$http.post('/xxx/xxx').then(({ data: res }) => { //處理返回結果 }).catch((err) => { //處理異常情況 }) }
現在我們要把它改造成受限制的網絡請求,假設並發請求上限設為10個,並起名叫limitRequest.js。實現如下:
// 並發隊列 import { LimitPromise } from '@/utils/limit-promise.js' // 請求上限 const MAX = 10 // 核心控制器 const limitP = new LimitPromise(MAX) //請求方法 function requestDemo(){ this.$http.post('/xxx/xxx').then(({ data: res }) => { //處理返回結果 }).catch((err) => { //處理異常情況 }) } //執行 function run(){ for(let i=0;i<100;i++){ // 上傳 limitP.call(this.requestDemo, params1,params2) } }
