前端js并發(fā)控制實現(xiàn)

在開發(fā)中, 我們經(jīng)常會遇到多個請求同時進行的需求,請求不多時,我們可以直接使用Promise.all()來進行并發(fā)請求,一般也不會有問題,但是這樣也會有弊端,比如:

  1. 其中一個請求比較慢,那么所有的請求就需要等待。
  2. 一個請求出錯,那么就代表Promise.all()失敗,不利于后續(xù)邏輯處理。
  3. http1.1一個域名只能同時有6個請求,當(dāng)同時并發(fā)請求比較多時,多余的請求,需要等待別的請求完成,而Promise.all()又需要等所有請求完成,所以會更慢。
  4. 請求數(shù)量過多,頁面上的功能又需要逐步渲染顯示,而不是等待所有接口完成。

所以,基于上面這些問題我們就需要控制請求的并發(fā),以下就是并發(fā)控制的基本代碼,同時為了方便再一個頁面中,會有多個功能模塊中需要并發(fā)控制,在RequestQueue類外面多封裝了一層。

// 并發(fā)控制
class RequestQueue {
  /**
   * @param {number} concurrence
   */
  constructor(concurrence = 4) {
    // 默認設(shè)置并發(fā)數(shù)量
    this.concurrence = concurrence < 4 ? 4 : concurrence;
    // 任務(wù)隊列
    this.queue = [];
    // 正在執(zhí)行的任務(wù)數(shù)
    this.runing = 0;
    // 是否暫停
    this.isPause = false;
  }

  /**
   * 加入請求任務(wù)
   * @param {funtion} fn 請求任務(wù)
   * @returns {void}
   */
  join(fn) {
    if (typeof fn !== 'function') {
      console.log('請?zhí)砑右粋€函數(shù)?。?!');
      return;
    }

    if (this.isPause || this.runing >= this.concurrence) {
      this.queue.push(fn);
      return;
    }

    this.excute(fn)
  }
  /**
   * 執(zhí)行函數(shù)
   * @param {function} fn fn
   * @returns {void}
   */
  async excute(fn) {
    // 正在執(zhí)行的數(shù)量增加
    this.runing += 1;
    try {
      await fn();
    } catch (error) {
      console.log('requestQueue執(zhí)行請求報錯~~~');
    } finally {
      this.runing -= 1;
      this.next();
    }
  }
  /**
   * 下一個
   * @returns {void}
   */
  next() {
    if (this.isPause || this.runing >= this.concurrence || !this.queue.length) {
      return;
    }
    const fn = this.queue.shift();
    this.excute(fn);
  }
  /**
   * 暫停
   * @returns {void}
   */
  pause() {
    this.isPause = true;
  }
  /**
   * 恢復(fù)
   * @returns {void}
   */
  resume() {
    this.isPause = false;
    this.next();
  }
  /**
   * 清理
   * @returns {void}
   */
  clear() {
    this.isPause = false;
    this.queue = [];
    this.runing = 0;
  }
}

const requestQueueMap = new Map();
/**
 * 不同命名空間并發(fā)請求隊列
 */
class NamespaceRequestQueue {
  /**
   * @param {string} name 命名空間
   * @param {number} concurrence 并發(fā)量
   */
  constructor(name, concurrence) {
    this.namespace = name;
    let rq = requestQueueMap.get(name);
    if (!rq) {
      rq = new RequestQueue(concurrence);
      requestQueueMap.set(name, rq);
    }
    // 當(dāng)前的請求隊列
    this.requestQueue = rq;
  }

  join(fn) {
    this.requestQueue.join(fn);
  }

  next() {
    this.requestQueue.next();
  }

  pause() {
    this.requestQueue.pause();
  }

  resume() {
    this.requestQueue.resume();
  }

  clear() {
    this.requestQueue.clear()
  }

  /**
   * 銷毀,清空所有命名空間的并發(fā)控制
   */
  destroy() {
    this.requestQueue = null;
    this.namespace = '';
    for (const instance of requestQueueMap.values()) {
      instance.clear();
    }
    requestQueueMap.clear();
  }
}

export {
  RequestQueue,
}

export default NamespaceRequestQueue;

主要有兩個類RequestQueueNamespaceRequestQueue,其中主要功能為RequestQueue類,NamespaceRequestQueue可以通過命名空間,控制不同的并發(fā)功能模塊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 開發(fā)go程序的時候,時常需要使用goroutine并發(fā)處理任務(wù),有時候這些goroutine是相互獨立的,而有的時...
    駐馬聽雪閱讀 2,579評論 0 21
  • 簡述ETCD及其特點? etcd 是 CoreOS 團隊發(fā)起的開源項目,是一個管理配置信息和服務(wù)發(fā)現(xiàn)(servic...
    成淺閱讀 413評論 0 1
  • Linux設(shè)備驅(qū)動中必須解決的一個問題是多個進程對共享資源的并發(fā)訪問,并發(fā)的訪問會導(dǎo)致競態(tài),即使是經(jīng)驗豐富的驅(qū)動工...
    konishi5202閱讀 915評論 1 6
  • 1、什么是兼容性測試?兼容性測試側(cè)重哪些方面? 參考答案: 兼容測試主要是檢查軟件在不同的硬件平臺、軟件平臺上是否...
    電擊小子_ea1b閱讀 1,674評論 1 1
  • 弄清楚kafka的網(wǎng)絡(luò)模型原理,能很好的幫助理解和優(yōu)化kafka服務(wù)。kafka底層的網(wǎng)絡(luò)通信,沒有使用第三方rp...
    外星人rsz閱讀 3,468評論 0 4

友情鏈接更多精彩內(nèi)容