記一道控制並行數的前端面試題

追_光_者發表於2019-03-13

題目:請實現如下函式,可以批量請求資料,所有的 url 地址在 urls 引數中,同時可以通過 max 引數控制請求的並行數,當所有請求結束之後,需要執行 callback 回撥函式,傳送請求的函式可以直接使用 fetch 即可

function sendRequest(urls: strind[], max: number, callback: () => void) {

}
複製程式碼

思路分析:

  1. 通過批量並且當所有請求結束後,在執行 callback 我們初步確定使用 Promise.all 可以實現此功能,
  2. 由於請求地址在 urls 陣列中,因為是一個並行的問題,所以我們可以將請求地址進行按照 max 來進行分組,最後得到多少組就執行多少次請求

具體程式碼實現:

    let bodyElement = document.body
    let urls = [
      'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2580986389,1527418707&fm=27&gp=0.jpg',
      'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1995874357,4132437942&fm=27&gp=0.jpg',
      'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2640393967,721831803&fm=27&gp=0.jpg',
      'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1548525155,1032715394&fm=27&gp=0.jpg',
      'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2434600655,2612296260&fm=27&gp=0.jpg',
      'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2160840192,133594931&fm=27&gp=0.jpg'
    ]
    let max = 4
    let callback = () => {
      console.log('所有請求完成了')
    }
    // 定義一個分組函式 已 max 為最大個數儲存在一個物件中
    let group = (urls, max) => {
      let groupObj = {}
      
      urls.forEach((item, index) => {
        let group = parseInt(index / max)
        if (groupObj[group]) {
          return groupObj[group].push(item)
        }
        groupObj[group] = [item]
      })
      
      return groupObj
    }
    
    function sendRequest(urls, max, callback) {
      let groupResult = group(urls, max)
      let currentIndex = 0
      // 使用 fetch 封裝請求
      let getFetch = source => {
        return source.map(item => fetch(item).then(res => res.blob()))
      }
      let send = () => {
        //  判斷有沒有當前組
        groupResult[currentIndex] &&
        Promise.all(getFetch(groupResult[currentIndex]))
          .then((body) => {
            callback()
            currentIndex++
            console.log(body, `第${currentIndex}次批量請求成功`)
            
            let html = ''
            
            body.forEach(item => {
              html += `<img src=${URL.createObjectURL(item)} />`
            })
            bodyElement.innerHTML += html
            
            // 用延時器是因為反應介面太快 以便於觀察
            setTimeout(() => {
              send()
            }, 1000)
          })
          .catch((err) => {
            console.log('error')
          })
      }

      send()
    }
    
    sendRequest(urls, max, callback)
複製程式碼
功能已實現,大家有什麼好的實現方法可以評論下,敬請指教。複製程式碼

相關文章