寫爬蟲時遇到用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) }) }