請排好隊,一個一個的來 --- 基於Promise.all()實現併發控制

前言

前幾天看了做者 zz_jesse 的 寫給新手前端的各類文件上傳攻略,從小圖片到大文件斷點續傳  ,學習了不少有關上傳的知識點。但在大文件分片上傳一塊,做者有說起分片上傳須要作併發限制處理,但他的demo並無作。抱着學習的心態,我又去網上學習了一番。。javascript


Promise.all()

Promise.all() 方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。前端

const p = Promise.all([p1, p2, p3]);
複製代碼

上面代碼中, Promise.all() 方法接受一個數組做爲參數,p一、p二、p3都是 Promise 實例,若是不是,就會先調用下面講到的 Promise.resolve 方法,將參數轉爲 Promise 實例,再進一步處理。另外, Promise.all() 方法的參數能夠不是數組,但必須具備 Iterator 接口,且返回的每一個成員都是 Promise 實例。 p的狀態由p一、p二、p3決定,分紅兩種狀況。java

  • 只有p一、p二、p3的狀態都變成 fulfilled ,p的狀態纔會變成 fulfilled ,此時p一、p二、p3的返回值組成一個數組,傳遞給p的回調函數。
  • 只要p一、p二、p3之中有一個被 rejected ,p的狀態就變成 rejected ,此時第一個被 reject 的實例的返回值,會傳遞給p的回調函數。

Code

  const requestsLimit = (list, limit, asyncHandle) => {
    return new Promise(resolve => {
      let _limit = limit;
      let recordList = []; // 記錄異步操做
      let index = 0;
      let listCopy = [].concat(list);
      let asyncList = []; // 正在進行的全部併發異步操做


      const asyncFunc = () => {
        while(_limit--) {
          const data = listCopy.shift()
          if (data) asyncList.push(asyncHandle(data, index++)); 
        }
        
        Promise.all(asyncList).then(response => {
          // 監聽並記錄每一次請求的結果
          recordList = recordList.concat(response.filter(item => item));


          if (listCopy.length !== 0) {
            _limit = limit;
            asyncList = [];
            asyncFunc() // 數組還未迭代完,遞歸繼續進行迭代
          } else {
            // 全部併發異步操做都完成後,本次併發控制迭代完成,返回記錄結果
            resolve(recordList)
          }
        })
      }


      asyncFunc()
    })
  }

複製代碼

Demo

  var dataLists = [1,2,3,4,5,6,7,8];
  
  requestsLimit(dataLists, 3, (item, index) => {
    return new Promise(resolve => {
      // 執行異步處理
      setTimeout(() => {
        // 篩選異步處理的結果
        console.log(index)
        if (item % 2 === 0) resolve({ item, index })
        else resolve()
      }, Math.random() * 5000)  
    });
  }).then(response => {
    console.log('finish', response)
  })
複製代碼

console.log() git

傳送門

相關文章
相關標籤/搜索