Promise.all請求失敗重發功能的實現

寫爬蟲時遇到用Promise.all同時請求多個頁面,不可避免的會遇到某些請求失敗的狀況,這時能夠實現一個「重發失敗請求」的功能。數組

Promise.all(task).then().catch() 會在全部task都resolve時纔會進then方法,而且把全部結果以一個數組返回。只要有一個失敗,就會進catch。但若是在單個請求中定義了catch方法,就不會進Promise.all的catch方法。所以,能夠在單個的catch中將失敗的promise放入一個list,待一輪請求完成後,再去請求失敗的請求。promise

let failedList = []

function getDataById (id) { // 這是單個請求
  return new Promise(function (resolve, reject) {
    getResponse(id, resolve, reject)
  }).catch(e => {
    failedList.push(getDataById (id)) // 若是失敗,就從新發起請求,並將該請求放入failedList中以便後續處理
  })
}

function getResponse (id, resolve, reject) { // 模擬返回結果
  setTimeout(() => {
    if (Math.random() > 0.8) resolve({id, msg: 'ok'})
    else reject({id, msg: 'error'})
  }, 1000)
}


const RequestList = [getDataById(1), getDataById(2), getDataById(3)]

handlePromiseDone(RequestList)

let requestTime = 1 // 當前請求次數
let maxRequestTime = 5 // 最大重試次數
let result = [] // 最後的結果

function handlePromiseDone(requestList) { // 處理請求結果
  Promise.all(requestList).then(resolve => {
    result = result.concat(resolve.filter(i => i !== undefined)) // 過濾掉resolve列表裏的失敗請求的結果
    let failedLength = failedList.length
    if (failedLength > 0 && requestTime < maxRequestTime) { // 若是失敗列表裏有請求,而且請求次數不超過設定的值,就進行下一次請求
      console.log(`第${requestTime}次請求完成,其中成功${RequestList.length - failedLength}個,失敗${failedLength}個,正在進行第${++requestTime}次請求...`)
      handlePromiseDone(failedList)
      failedList = [] // 清空本輪請求的failedList
    } else { // 表示全部請求都成功了,或者達到了最大請求次數。到這裏就能夠對result作進一步處理了。
      console.log(`請求完成,共請求${requestTime}次, 其中成功${RequestList.length - failedLength}個,失敗${failedLength}個\n`, result)
    }
  }).catch(e => {
    console.log(e)
  })
}

相關文章
相關標籤/搜索