不到50行代碼實現一個能對請求併發數做限制的通用RequestDecorator

来源:https://www.cnblogs.com/chenjg/archive/2018/09/13/9638613.html
-Advertisement-
Play Games

使用場景 在開發中,我們可能會遇到一些對非同步請求數做併發量限制的場景,比如說微信小程式的request併發最多為5個,又或者我們需要做一些批量處理的工作,可是我們又不想同時對伺服器發出太多請求(可能會對伺服器造成比較大的壓力)。這個時候我們就可以對請求併發數進行限制,並且使用排隊機制讓請求有序的發送 ...


使用場景

在開發中,我們可能會遇到一些對非同步請求數做併發量限制的場景,比如說微信小程式的request併發最多為5個,又或者我們需要做一些批量處理的工作,可是我們又不想同時對伺服器發出太多請求(可能會對伺服器造成比較大的壓力)。這個時候我們就可以對請求併發數進行限制,並且使用排隊機制讓請求有序的發送出去。

介紹

那麼,接下來我們就來講一下如何實現一個通用的能對請求併發數進行限制的RequestDecorator。我們先來介紹一下它的功能:

  1. 既然涉及到併發數限制,它就肯定允許用戶傳入最大併發數限制參數:maxLimit
  2. 既然是一個通用的RequestDecorator,那麼它應該允許使用者傳入其喜歡的非同步api(比如ajax, fetch, axios等)。
  3. 為了方便起見,也為了開發便利性,被RequestDecorator封裝後的request請求結果都返回一個promise。
  4. 由於使用者傳入的非同步api不一定是promise類型的,也可能是callback類型的,因此我們提供用戶一個needChange2Promise參數,使用者若傳入的是callback類型的api,它可以通過將這個參數設置為true來將callback類型轉化為promise類型。

分析完功能後,接下來我們就來實現這個東西:

實現

具體代碼如下,每一步我基本都做了註釋,相信大家能看懂。

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;

樣例代碼如下:

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就已經實現了。當然,這裡還有很多可以繼續增加的功能點,比如

  1. 允許使用者設置每個請求的retry次數。
  2. 允許使用者對每個請求設置緩存處理。

優點:

  1. 不修改用戶原來的request api代碼。對原有代碼無副作用。
  2. 不修改request api的調用方式。用戶可以無縫的使用被RequestDecorator封裝過的request。
  3. 可擴展,後續可能不止支持併發量限制,還可能增加緩存、retry等額外的功能。

結語

以上,就是本篇的全部內容。github倉庫地址點擊這裡。歡迎大家點贊或者star下。如果大家有興趣的話,也可以一起來完善這個東西。這個項目還不成熟,可能還會有bug,歡迎大家在github上提issue幫助我完善它。如果覺得有幫助的話,麻煩點個贊哦,謝謝。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 資料庫存儲引擎是資料庫底層軟體組織,資料庫管理系統(DBMS)使用數據引擎進行創建、查詢、更新和刪除數據。不同的存儲引擎提供不同的存儲機制、索引技巧、鎖定水平等功能,使用不同的存儲引擎,還可以 獲得特定的功能。現在許多不同的資料庫管理系統都支持多種不同的數據引擎。MySQL的核心就是存儲引擎。 ...
  • MySQL InnoDB的二級索引(Secondary Index)會自動補齊主鍵,將主鍵列追加到二級索引列後面。詳細一點來說,InnoDB的二級索引(Secondary Index)除了存儲索引列key值,還存儲著主鍵的值(而不是指向主鍵的指針)。為什麼這樣做呢?因為InnoDB是以聚集索引方式組... ...
  • 最近遇到的死鎖問題都發生在併發操作單張表上,比較有意思,就模擬了重現了一下。根據非聚集索引為條件,刪除某一個表的數據,類似於這麼一個語句,delete from table where nocluster_index in (x,y,z,m,n……)in裡面的內容不同,併發執行某些情況下,可能會引發 ...
  • to_timestamp('2011-11-11 11:11:11.1','yyyy-mm-dd hh24:mi:ss.ff') ...
  • 聚集索引添加規則 聚集索引按下列方式實現 PRIMARY KEY 和 UNIQUE 約束 在創建 PRIMARY KEY 約束時,如果不存在該表的聚集索引且未指定唯一非聚集索引,則將自動對一列或多列創建唯一聚集索引。 主鍵列不允許空值。 在創建 UNIQUE 約束時,預設情況下將創建唯一非聚集索引, ...
  • 我自己的經歷:剛開始大數據是看書,一頁頁的看書,因為身邊有一個好的資源,有問題可以問我朋友,後來發現看大數據的零基礎書籍很難看下去,很多專業的東西對於一個新手根本就看不懂,沒有什麼效率。(在這裡我個人建議,初學不要看書,我的建議是學完一部分後用書去溫習,這樣很多東西都可以明白,並且可以查缺補漏) 學 ...
  • 在Editext的佈局屬性上加上 android:textCursorDrawable="@drawable/cursor_shape" cursor_shape如下: 事實證明:設置android:height無效,應該用padding的方法。 top設置為-2dp :讓游標頂部下移2dp bot ...
  • 一.Android studio的安裝 我們可以從中文社區http://www.android-studio.org/下載Android studio最新版本,然後點擊安裝即可。 之後我們直接運行android-studio它會先報錯因為缺少SDK,接著我們點擊安裝即可,建議在安裝sdk的時候選擇好 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...