中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中怎么實現并發控制

發布時間:2021-06-28 11:17:05 來源:億速云 閱讀:205 作者:小新 欄目:web開發

這篇文章給大家分享的是有關JavaScript中怎么實現并發控制的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

在日常開發過程中,你可能會遇到并發控制的場景,比如控制請求并發數。那么在 JavaScript 中如何實現并發控制呢?在回答這個問題之前,我們來簡單介紹一下并發控制。

假設有 6 個待辦任務要執行,而我們希望限制同時執行的任務個數,即最多只有 2 個任務能同時執行。當 正在執行任務列表 中的任何 1 個任務完成后,程序會自動從 待辦任務列表 中獲取新的待辦任務并把該任務添加到 正在執行任務列表 中。為了讓大家能夠更直觀地理解上述的過程,阿寶哥特意畫了以下 3 張圖:

1.1 階段一

JavaScript中怎么實現并發控制

1.2 階段二

JavaScript中怎么實現并發控制

1.3 階段三

JavaScript中怎么實現并發控制

好的,介紹完并發控制之后,阿寶哥將以 Github 上 async-pool 這個庫來介紹一下異步任務并發控制的具體實現。

async-pool:https://github.com/rxaviers/async-pool

Run multiple promise-returning & async functions with limited concurrency using native ES6/ES7。

二、并發控制的實現

async-pool 這個庫提供了 ES7 和 ES6 兩種不同版本的實現,在分析其具體實現之前,我們來看一下它如何使用。

2.1 asyncPool 的使用
const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i));
await asyncPool(2, [1000, 5000, 3000, 2000], timeout);

在以上代碼中,我們使用 async-pool 這個庫提供的 asyncPool 函數來實現異步任務的并發控制。 asyncPool 函數的簽名如下所示:

function asyncPool(poolLimit, array, iteratorFn){ ... }

該函數接收 3 個參數:

  • poolLimit(數字類型):表示限制的并發數;

  • array(數組類型):表示任務數組;

  • iteratorFn(函數類型):表示迭代函數,用于實現對每個任務項進行處理,該函數會返回一個 Promise 對象或異步函數。

對于以上示例來說,在使用了 asyncPool 函數之后,對應的執行過程如下所示:

const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i));
await asyncPool(2, [1000, 5000, 3000, 2000], timeout);
// Call iterator (i = 1000)
// Call iterator (i = 5000)
// Pool limit of 2 reached, wait for the quicker one to complete...
// 1000 finishes
// Call iterator (i = 3000)
// Pool limit of 2 reached, wait for the quicker one to complete...
// 3000 finishes
// Call iterator (i = 2000)
// Itaration is complete, wait until running ones complete...
// 5000 finishes
// 2000 finishes
// Resolves, results are passed in given array order `[1000, 5000, 3000, 2000]`.

通過觀察以上的注釋信息,我們可以大致地了解 asyncPool 函數內部的控制流程。下面我們先來分析 asyncPool 函數的 ES7 實現。

關注「全棧修仙之路」閱讀阿寶哥原創的 4 本免費電子書(累計下載 3萬+)及 50 幾篇 TS 系列教程。

2.2 asyncPool ES7 實現
async function asyncPool(poolLimit, array, iteratorFn) {
  const ret = []; // 存儲所有的異步任務
  const executing = []; // 存儲正在執行的異步任務
  for (const item of array) {
    // 調用iteratorFn函數創建異步任務
    const p = Promise.resolve().then(() => iteratorFn(item, array));
    ret.push(p); // 保存新的異步任務

    // 當poolLimit值小于或等于總任務個數時,進行并發控制
    if (poolLimit <= array.length) {
      // 當任務完成后,從正在執行的任務數組中移除已完成的任務
      const e = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e); // 保存正在執行的異步任務
      if (executing.length >= poolLimit) {
        await Promise.race(executing); // 等待較快的任務執行完成
      }
    }
  }
  return Promise.all(ret);
}

在以上代碼中,充分利用了 Promise.allPromise.race 函數特點,再結合 ES7 中提供的 async await 特性,最終實現了并發控制的功能。利用 await Promise.race(executing); 這行語句,我們會等待 正在執行任務列表 中較快的任務執行完成之后,才會繼續執行下一次循環。

asyncPool ES7 實現相對比較簡單,接下來我們來看一下不使用 async await 特性要如何實現同樣的功能。

2.3 asyncPool ES6 實現
function asyncPool(poolLimit, array, iteratorFn) {
  let i = 0;
  const ret = []; // 存儲所有的異步任務
  const executing = []; // 存儲正在執行的異步任務
  const enqueue = function () {
    if (i === array.length) {
      return Promise.resolve();
    }
    const item = array[i++]; // 獲取新的任務項
    const p = Promise.resolve().then(() => iteratorFn(item, array));
    ret.push(p);

    let r = Promise.resolve();

    // 當poolLimit值小于或等于總任務個數時,進行并發控制
    if (poolLimit <= array.length) {
      // 當任務完成后,從正在執行的任務數組中移除已完成的任務
      const e = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e);
      if (executing.length >= poolLimit) {
        r = Promise.race(executing); 
      }
    }
 
    // 正在執行任務列表 中較快的任務執行完成之后,才會從array數組中獲取新的待辦任務
    return r.then(() => enqueue());
  };
  return enqueue().then(() => Promise.all(ret));
}

在 ES6 的實現版本中,通過內部封裝的 enqueue 函數來實現核心的控制邏輯。當 Promise.race(executing) 返回的 Promise 對象變成已完成狀態時,才會調用 enqueue 函數,從 array 數組中獲取新的待辦任務。

三、阿寶哥有話說

asyncPool 這個庫的 ES7 和 ES6 的具體實現中,我們都使用到了 Promise.allPromise.race 函數。其中手寫 Promise.all 是一道常見的面試題。剛好趁著這個機會,阿寶哥跟大家一起來手寫簡易版的 Promise.allPromise.race 函數。

3.1 手寫 Promise.all

Promise.all(iterable) 方法會返回一個 promise 對象,當輸入的所有 promise 對象的狀態都變成 resolved 時,返回的 promise 對象就會以數組的形式,返回每個 promise 對象 resolve 后的結果。當輸入的任何一個 promise 對象狀態變成 rejected 時,則返回的 promise 對象會 reject 對應的錯誤信息。

Promise.all = function (iterators) {
  return new Promise((resolve, reject) => {
    if (!iterators || iterators.length === 0) {
      resolve([]);
    } else {
      let count = 0; // 計數器,用于判斷所有任務是否執行完成
      let result = []; // 結果數組
      for (let i = 0; i < iterators.length; i++) {
        // 考慮到iterators[i]可能是普通對象,則統一包裝為Promise對象
        Promise.resolve(iterators[i]).then(
          (data) => {
            result[i] = data; // 按順序保存對應的結果
            // 當所有任務都執行完成后,再統一返回結果
            if (++count === iterators.length) {
              resolve(result);
            }
          },
          (err) => {
            reject(err); // 任何一個Promise對象執行失敗,則調用reject()方法
            return;
          }
        );
      }
    }
  });
};

需要注意的是對于 Promise.all 的標準實現來說,它的參數是一個可迭代對象,比如 Array、String 或 Set 等。

3.2 手寫 Promise.race

Promise.race(iterable) 方法會返回一個 promise 對象,一旦迭代器中的某個 promise 對象 resolvedrejected,返回的 promise 對象就會 resolve 或 reject 相應的值。

Promise.race = function (iterators) {
  return new Promise((resolve, reject) => {
    for (const iter of iterators) {
      Promise.resolve(iter)
        .then((res) => {
          resolve(res);
        })
        .catch((e) => {
          reject(e);
        });
    }
  });
};

本文阿寶哥帶大家詳細分析了 async-pool 異步任務并發控制的具體實現,同時為了讓大家能夠更好地理解 async-pool 的核心代碼。最后阿寶哥還帶大家一起手寫簡易版的 Promise.allPromise.race 函數。其實除了 Promise.all 函數之外,還存在另一個函數 —— Promise.allSettled,該函數用于解決 Promise.all 存在的問題,感興趣的小伙伴可以自行研究一下。

感謝各位的閱讀!關于“JavaScript中怎么實現并發控制”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

栖霞市| 镇原县| 日照市| 德安县| 阜新市| 友谊县| 沾化县| 靖州| 大英县| 嘉鱼县| 长乐市| 福建省| 台南市| 横山县| 冷水江市| 政和县| 日喀则市| 保康县| 闻喜县| 渭源县| 郯城县| 兖州市| 忻州市| 江西省| 瑞安市| 巴东县| 安福县| 公主岭市| 栾川县| 文昌市| 潮安县| 宾阳县| 微山县| 图片| 曲水县| 荔波县| 钟祥市| 洮南市| 体育| 县级市| 庆安县|