写爬虫时遇到用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) }) }