Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第五题:Promise all 错误处理 #6

Closed
KieSun opened this issue Mar 11, 2021 · 42 comments
Closed

第五题:Promise all 错误处理 #6

KieSun opened this issue Mar 11, 2021 · 42 comments

Comments

@KieSun
Copy link
Owner

KieSun commented Mar 11, 2021

异步请求通过 Promise.all 处理,怎么让其中失败的所有请求重试。

Promise.all([A, B, C, D])
// 4 个请求完成后发现 AD 请求失败了,如果让 AD 请求重试

新建了一个大厂真题每日打卡群,有意愿学习打卡的再进,群已达扫码上线,请加好友拉你进群

@secret344
Copy link

let rejarr = [];
const httprequest = function (type, time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            Math.random() * 1000 > time
                ? resolve(type)
                : reject({ type, time });
        }, time);
    }).catch((rej) => {
        rejarr.push(httprequest(rej.type, rej.time));
    });
};
let p1 = httprequest("A", Math.random() * 1000);
let p2 = httprequest("B", Math.random() * 1000);
let p3 = httprequest("C", Math.random() * 1000);
let p4 = httprequest("D", Math.random() * 1000);

let all = (arr) => {
    Promise.all(arr).then((res) => {
        if (rejarr.length) {
            all(rejarr);
            rejarr = [];
        }
    });
};
all([p1, p2, p3, p4]);

@goldEli
Copy link

goldEli commented Mar 12, 2021

// 模拟第一次请求失败
const error = {
  A: true,
  D: true
};

function getData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // 模拟第一次请求失败
      if (error[url]) {
        error[url] = false;
        reject(url);
      } else {
        resolve(url);
      }
    }, 0);
  });
}

function retryRequest(promise, retryNum) {
  return new Promise((resolve, reject) => {
    promise()
      .then((data) => resolve(data))
      .catch((error) => {
        if (retryNum > 0) {
          retryRequest(promise, retryNum - 1);
        } else {
          reject(error);
        }
      });
  });
}

function handleAll() {
  return new Promise((resolve, reject) => {
    Promise.all([getData("A"), getData("B"), getData("C"), getData("D")])
      .then((data) => {
        console.log("请求返回的结果", data);
        resolve(data);
      })
      .catch((error) => {
        console.log(`${error}, 请求失败,开始重试`);
        reject(error);
      });
  });
}

retryRequest(handleAll, 1);

@XianHuiDeDiZhongHai
Copy link

const requestInterface =
  (name, time, isSuccess) =>
  new Promise((resolve, reject) => {
    setTimeout((name) => {
      isSuccess ? resolve(name) : reject()
    }, time, name)
  }).catch(err => requestInterface(name, time, true))

const A = requestInterface('A', 500, false)

const B = requestInterface('B', 1000, true)

const C = requestInterface('C', 1500, true)

const D = requestInterface('D', 800, false)


Promise.all([A, B, C, D])
  .then((params) => void console.log('成功', params))
  .catch(error => void console.log('失败', error))

@1742284240
Copy link

1742284240 commented Mar 12, 2021

  function http(value, flag){
    return new Promise((resolve, reject)=>{
      setTimeout(()=>{
        if(Math.random() < 0.5){ // 设定一个成功或者失败的条件
          resolve(value)
          console.log(flag?'重新请求成功':'第一次请求成功',value)
        }else{
          console.log(flag?'重新请求失败':'第一次请求失败',value)
          resolve(http(value,true))
        }
      }, Math.random()*2000)
    })
  }
  let A = http('A');
  let B = http('B');
  let C = http('C');
  let D = http('D');

  Promise.all([A,B,C,D]).then(res=>{
    console.log('成功',res)
  })

Edit promiss.all错误处理

image

@cduyzh
Copy link

cduyzh commented Mar 12, 2021

promise.all

这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。
失败/拒绝(Rejection):
如果传入的 promise 中有一个失败(rejected),Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成。

function wait(duration) {
  return new Promise((resolve) => setTimeout(resolve, duration * 1000));
}

function getRandomIntInclusive(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
}

async function requestB(name) {
  await wait(getRandomIntInclusive(1, 5));
  try {
    if (getRandomIntInclusive(1, 5) > 2) {
      throw `${name} function wrong`;
    }
    return new Promise((resolve) => resolve(name));
  } catch (error) {
    console.log("requestB error", error);
    console.log(`function ${name} retry`);
    return requestB(name);
  }
}

async function doFunB(functionName) {
  console.log(`doFunB start ${functionName}`);
  return await requestB(functionName);
}

async function testB() {
  const res = await Promise.all([
    doFunB("A"),
    doFunB("B"),
    doFunB("C"),
    doFunB("D"),
  ]);
  console.log("res", res);
}

testB();


结果

[Running] node "e:\coding\inspiration-git\vite-vue3\tempCodeRunnerFile.javascript"
doFunB start A
doFunB start B
doFunB start C
doFunB start D
requestB error A function wrong
function A retry
requestB error D function wrong
function D retry
res [ 'A', 'B', 'C', 'D' ]

[Done] exited with code=0 in 5.13 seconds

@learnRy
Copy link

learnRy commented Mar 12, 2021

//经过一层包装把失败请求的返回回去
async function allError(p) {
  try {
    const res = await p
    return 0
  }catch(e) {
    return p
  }
}
Promise.all([A, B, C, D].map(item => allError(item))).then(arr => {
  const item = arr.filter(list => list !== 0)
  if(item && item.length) {
    Promise.all(item).then(() => {
      console.log('又试一次成功了')
    })
  }
}).catch(err => {
  console.log(err)
})

@panalanjun
Copy link

待完善的优化

对于失败的请求,目前使用index作为固定的标识,只会重复请求多一次

var index = -1;	// 模拟下标0和2请求失败,失败的请求只重复请求多一次
var failArr = [];	// 记录失败的请求

function Request(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
	index++;
	if (index === 0 || index === 2) {
		console.log("失败", name);
		reject(name);
	} else {
		console.log("成功", name);
		resolve(name);
	}
		}, randomTime());
	}).catch(e => {
		console.log("promise catch", e);
		failArr.push(name);
	});
}

function randomTime() {
	return Math.round(Math.random() * 1000);
}


// Test:异步请求通过 Promise.all 处理,怎么让其中失败的所有请求重试。
function Test() {
	Promise.all([Request('A'), Request('B'), Request('C'), Request('D')]).then(res => {
		failArr.forEach((item, index) => {
			Request(item);
		});
	}).catch(e => {
		console.log("promiseAll Error", e);
	});
}

Test();

@huangpingcode
Copy link

function mockHttp(str, time = 0.5, flag = false) {
    return new Promise((resolve, reject) => {
        let isSuccess = flag || Math.random() > 0.5
        setTimeout(() => {
            console.log('mockHttp str, isSuccess -> ', str, isSuccess);
           isSuccess ? resolve(str) : reject();
        }, time * 1000);
    });
}

Promise.all([
    mockHttp('A').catch(() => mockHttp('A', true)),
    mockHttp('B').catch(() => mockHttp('B', true)),
    mockHttp('C').catch(() => mockHttp('C', true)),
    mockHttp('D').catch(() => mockHttp('D', true)),
]).then(res => {
    console.log(res);
})

@vandvassily
Copy link

// 异步请求通过 Promise.all 处理,怎么让其中失败的所有请求重试。

// Promise.all([A, B, C, D])
// 4 个请求完成后发现 AD 请求失败了,如果让 AD 请求重试

function request(name, count = 0) {
    return new Promise((resolve, reject) => {
        const isSuccess = Math.random() > 0.5;
        console.log(`接口${name}: ${isSuccess}`);
        setTimeout(() => {
            isSuccess > 0.5 ? resolve(name) : reject(name);
        }, Math.random() * 1000);
    }).catch((err) => {
        count++;

        if (count > 2) {
            return Promise.reject(`后端大爷${name}接口写的666`);
        }
        return request(name, count);
    });
}

let queue = [request('A'), request('B'), request('C'), request('D')];

Promise.all(queue)
    .then((arr) => {
        console.log(arr);
    })
    .catch((err) => {
        console.log(err);
    });

@Ecaknight
Copy link

function retryRequest (arr = []) {
    Promise.all(arr).then(res => {
      console.log('成功', res)
    }).catch(err => {
      console.log('失败', err)
    })
  }

  function getRandomTime() {
    return Math.ceil(Math.random() * 2000) + 100
  }

  function request (data) {
    return new Promise((resolve, reject) => {
      const time = getRandomTime()
      setTimeout(() => {
        if (time > 1000) {
        resolve(data)
      } else {
        reject(data)
      }
      }, time)
    }).catch(err => {
      return request(data)
    })
  }

  retryRequest([request('A'), request('B'), request('C'), request('D')])

@free-qiaochen
Copy link

function http (value, flag) {
  return new Promise((r, j) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (Math.random() < 0.5) { // 设定一个成功或者失败的条件
          resolve(value)
        } else {
          reject(value)
        }
      }, Math.random() * 2000)
    }).then((val) => {
      console.log(flag ? '重新请求成功' : '第一次请求成功', value)
      r(val)
    }, (rejVal) => {  // 失败的请求,再次调用;
      console.log(flag ? '重新请求失败' : '第一次请求失败', value)
      r(http(rejVal, true))
    })

  })
}
let A = http('A');
let B = http('B');
let C = http('C');
let D = http('D');

Promise.all([A, B, C, D]).then(res => {
  console.log('成功', res)
})

@adam-zhou
Copy link

adam-zhou commented Mar 12, 2021

let rejectArr = []

function request(value) {
   return new Promise((resolve, reject)=> {
       if (成功)
         resolve(value)
       else(失败)
         reject(value)
   }).then(data=> {}) 
   .catch(err) {
       rejectArr.push(request(err.value))
   }
}


let _promiseAll = function(arr) {
  return Promise.all(arr).then((res)=> {
    if(rejectArr.length) {
       _promiseAll(rejectArr);
      rejectArr = []
    }
  })
}

@l0ng09
Copy link

l0ng09 commented Mar 12, 2021

/**
 * 异步请求通过 Promise.all 处理,怎么让其中失败的所有请求重试。
 * Promise.all([A, B, C, D])
 * 4 个请求完成后发现 AD 请求失败了,如何让 AD 请求重试
 */

const failedList = [];

const fetchData = (params) => {
  return new Promise((resolve, reject) => {
    response(params, resolve, reject);
  }).catch((error) => {
    // 这里的 error 其实就是 reject 过来的 parmas
    failedList.push(fetchData(error));
  });
};

// 模拟数据返回,有一定的几率失败
const response = (params, resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.6) {
      console.log(params + "执行失败,重试");
      reject(params);
    } else {
      console.log(params + "执行成功");
      resolve(params);
    }
  }, Math.random() * 2000);
};

const promiseList = [
  fetchData("A"),
  fetchData("B"),
  fetchData("C"),
  fetchData("D"),
];

let result = [];

const getPromiseAll = (arr) => {
  Promise.all(arr).then((res) => {
    result = result.concat(res);
		// 检查失败队列是否有失败的任务
    if (failedList.length > 0) {
      getPromiseAll(failedList);
      failedList.length = 0;
    } else {
      console.log(result.filter((item) => item !== undefined));
    }
  });
};

getPromiseAll(promiseList);

@abu-ab
Copy link

abu-ab commented Mar 12, 2021

 const request = function (type, isSuccess) {
        console.log(isSuccess, type);
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            if (isSuccess) {
              resolve(type);
            } else {
              reject(type);
            }
          }, 1000);
        }).catch((rej) => {
          request(rej, true);
        });
      };
      let A = request("A", false);
      let B = request("B", true);
      let C = request("C", false);
      let D = request("D", true);
      Promise.all([A, B, C, D])
        .then((res) => {
          console.log("成功", res);
        })
        .catch((rej) => {
          console.log("失败", rej);
     });

image

@pengpeng9413
Copy link

感觉这道题没啥意思

@SunshineZJJ
Copy link

  let errReq=[];
			    let A = Promise.reject('A').catch(err=>{errReq.push(err);});
				let B = Promise.resolve('B').catch(err=>{errReq.push(err);});
				let C = Promise.resolve('C').catch(err=>{errReq.push(err);});
				let D = Promise.reject('D').catch(err=>{errReq.push(err);});
			    Promise.all([A,B,C,D]).then(res => {
					res.forEach(e=>{
						console.log(!e?e+':请求失败!':e+':请求成功!')
					});
					if(errReq && errReq.length>0){
						errReq.forEach((e)=>{
							  Promise.resolve(e).then(res=>{  console.log("二次请求"+res+"---成功");});
						})
					}
					
			    });

@yang-1234
Copy link

let failedList = [];
    function getData(apiName, index) {
        if (index === 0) {
            failedList = []
        }
        return new Promise((resolve, reject) => {
            var time = Math.random() > 0.5  // 模拟请求成功、失败
            if (time) {
                resolve(`${apiName} 请求成功`)
            } else {
                failedList.push(apiName)
                resolve(`${apiName} 请求失败`)
            }
        })
    }
    let curRequestCount = 1 // 当前请求次数
    let maxRequestCount = 3 // 最大重试次数
    let curruntFailedList = []
    function sendRequest(again) {
        var promiseList = again ? curruntFailedList.map((item, index) => getData(item, index)) : ['A', 'B', 'C', 'D'].map(item => getData(item))
        return Promise.all(promiseList).then(values => {
            values.map((item, index) => {
                console.log(item)
            })
            curruntFailedList = failedList
            if (failedList.length > 0 && curRequestCount < maxRequestCount) {
                console.log('下一次执行准备....')
                ++curRequestCount
                sendRequest(true)
            } else {
                return
            }
        }).catch(error => {
            debugger
        })
    }
    sendRequest()

@yancongwen
Copy link

yancongwen commented Mar 12, 2021

请求失败自动重传机制

使用 tryRequest 方法将异步请求(promise)包裹,如果请求失败(reject)并且小于尝试次数,将自动尝试再次请求。

/*
 * @description 失败重试
 * @param request Promise 对象
 * @param times 设置的总尝试次数
 * @param time  第几次
 */
function tryRequest(request, times = 0, time = 1) {
    return request().catch(e => {
        if (time <= times) {
            console.log(e.message, `第${time}次重试`)
            return tryRequest(request, times, ++time)
        } else {
            return Promise.reject(e)
        }
    })
}

// 创建模拟请求
function creatMockRequest(name) {
    return () => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                if (Math.random() > 0.5) {
                    resolve(`${name} success`)
                } else {
                    reject(new Error(`${name} error`))
                }
            }, Math.random * 1000)
        })
    }
}

let requests = ['A', 'B', 'C', 'D'].map(item => {
    return tryRequest(creatMockRequest(item), 3)
})

Promise.all(requests).then(res => {
    console.log('成功了:', res)
}).catch(e => {
    console.log('失败了:', e.message)
})

image

@teefing
Copy link

teefing commented Mar 12, 2021

let requestList = {
  A: true,
  B: true,
  C: false,
  D: true
}

function request(key, res){
  let p = new Promise((resolve, reject) => {
    if(res) {
      // 如果请求成功就将请求从待请求对象中去除
      console.log('resolve', key)
      resolve(key)
      delete requestList[key]
    } 
    else {
      // 请求失败则保留请求在待请求对象中
      console.log('reject', key)
      reject(key)
    } 
  })
  return p
}

function retry(times = 5){
  return Promise.all(Object.keys(requestList).map(key => {
    let res = requestList[key]
    return request(key, res)
  })).then(res => {
    return 'success'
  }).catch(err => {
    if(times >= 1) return retry(times - 1)
    else throw('fail')
  })
}

retry().then(res => {
  console.log(res)
}).catch(err => {
  console.log(err)
})

输出

resolve A
resolve B
reject C
resolve D
reject C
reject C
reject C
reject C
reject C
fail

@GeekNoble
Copy link

let fail = []
let request = function(val, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (time < 1000) {
resolve(val)
} else {
reject(val)
}
}, time)
}).catch(data => {
console.log(data,'1')
return request(data, 500)
})
}
let A = request('A', 1100)
let B = request('B', 100)
let C = request('C', 500)
let D = request('D', 1100)
Promise.all([A,B,C,D]).then((val) => {
console.log(val, '成功')
})

@AbigaiL533
Copy link

function simulateRequest(value) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() * 10 > 5) {
        console.log('resolve', value);
        resolve(value);
      } else {
        console.log('reject', value);
        reject(value);
      }
    }, Math.floor(Math.random() * 1000));
  }).catch(e => {
    console.log(e, ';');
    simulateRequest(e);
  });
}

function allSettled(fn) {
  Promise.all(fn).then(res => {
    console.log(res);
  });
}

const p1 = simulateRequest('A');
const p2 = simulateRequest('B');
const p3 = simulateRequest('C');
const p4 = simulateRequest('D');
const fn = [p1, p2, p3, p4];

本来是想用promise.allSettled来做的,但是好像和这个的使用场景稍微有些区别,还得再去看看两者的使用场景

@mengzhe510
Copy link

let fn5 = function (params, count = 0) {
return new Promise((resolve, reject) => {
let time = Math.random() * 1000
const isSuccess = time < 0.5 * 1000
setTimeout(() => {
if (isSuccess) {
console.log(${params}${count?'重新':''}请求成功)
resolve(params)
} else {
reject(params)
}
},time)
}).catch((err) => {
console.log(${err}${count?'重新':''}请求失败)
if (count < 1) {
return fn5(err, 1)
}
return ''
})
}
let arr5 = ['A', 'B', 'C', 'D'].map(item => {
return fn5(item)
})
Promise.all(arr5).then(data => {
console.log('fn5:', data)
})

@chen870370470
Copy link

chen870370470 commented Mar 12, 2021

MDN解释: Promise.all()方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。

  return new Promise((resolve, reject) => {
    // 模拟异步请求
    setTimeout(() => {
      // 模拟请求结果
      if (Math.random() > 0.5) {
        // 如果请求成功则调用resolve
        resolve(value);
        // 使用flag来判断是第一次请求还是重新发起的请求
        console.log(flag ? "重新请求成功" : "第一次请求成功", value);
      } else {
        // 请求失败会打印哪个请求报的错,并且执行resolve再次发送请求
        console.log(flag ? "重新请求失败" : "第一次请求失败", value);
        resolve(sendPost(value, true));
      }
    }, Math.random() * 2000);
  });
}
let A = sendPost("A");
let B = sendPost("B");
let C = sendPost("C");
let D = sendPost("D");

Promise.all([A, B, C, D]).then((res) => {
  console.log("全部请求成功", res);
});

// 执行结果
// 第一次请求成功 B
// 第一次请求失败 D
// 重新请求失败 D
// 第一次请求成功 A
// 第一次请求失败 C
// 重新请求失败 D
// 重新请求成功 C
// 重新请求成功 D
// 全部请求成功 [ 'A', 'B', 'C', 'D' ]

@a11995910
Copy link

let req = function(data){
    return new Promise((reslove,reject)=>{
        //定义这里0.5以上为请求ok
        if(Math.random()>0.5){
            console.log(`${data}请求成功`);
            reslove(data);
        }else{
            reject(data);
        }
    }).catch((rej)=>{
        console.log(`${rej}请求失败,将重新发起`);
        return req(rej);
    })
}
Promise.all([req('a'),req('b'),req('c')]).then((res)=>{
    console.log(`请求结束 ${res}`)
})

@kevinxft
Copy link

// 参考了上面大兄弟的代码
const httpRequest = (tag, times = 3) =>
  new Promise((resolve, reject) => {
    const fn =
      Math.random() > 0.5
        ? () => resolve(tag)
        : () => reject({ tag, times: times - 1 })
    setTimeout(fn, parseInt(Math.random() * 1000), 10)
  }).catch(({ tag, times }) => {
    if (times > 0) {
      console.log(`${tag} 重试中...`)
      return httpRequest(tag, times)
    }
    return Promise.resolve()
  })

const test = async () => {
  const httpRequestArr = "ABCDEF".split("").map((item) => httpRequest(item, 3))
  const res = await Promise.all(httpRequestArr)
  console.log(res)
}

test()

@yangdong9527
Copy link

function request(params) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if(Math.random() > 0.5) {
        reject()
      } else {
        result.set(params, params)
        resolve(params)
      }
    }, Math.random() * 2000)
  })
  .catch(() => {
    // 如果请求失败在这里打个标记
    return 'error'
  })
}

let requestList = ['A','B','C','D']
let result = new Map()
let currTimes = 1
function handleRequestList(paramsArr) {
  if(currTimes === 1) {
    paramsArr.forEach(item => {
      result.set(item, '')
    })
  }
  let requestList = paramsArr.map(params => {
    return request(params)
  })
  Promise.all(requestList)
    .then(res => {
      // 筛选出失败的请求
      let failRes = []
      res.forEach((item,index) => {
        if(item === 'error') failRes.push(paramsArr[index]);
      })
      console.log(`这是第${currTimes}次请求`)
      if(failRes.length === 0) {
        // 没有请求失败的
        console.log('所有请求成功, 最终结果是', Array.from(result.values()))
        currTimes = 1
        result = []
      } else {
        // 有请求失败的
        currTimes++
        console.log('存在请求失败,稍后重试, 当前结果为', Array.from(result.values()))
        //重新请求
        handleRequestList(failRes)
      }
    })
}
handleRequestList(requestList)
PS C:\Users\Y_D\Desktop\daka> node index.js
这是第1次请求
存在请求失败,稍后重试, 当前结果为 [ 'A', '', '', 'D' ]
这是第2次请求
所有请求成功, 最终结果是 [ 'A', 'B', 'C', 'D' ]

@ErnestWangZuNian
Copy link

let errPromise: any[] = [];
const promiseError = (name: string, time = 3000) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(`error${name}`);
        }, time * Math.random())
    }).catch(error => {
        if (error.indexOf(name) > -1) {
            errPromise.push(promiseRight(name));
        }
    })
};

const promiseRight = (name: string, time = 4000) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(name);
        }, time * Math.random())
    });
};

const all = (promiseArray: any[]) => {
    Promise.all(promiseArray).then(res => {
        console.log(res, 'eeeee');
        //  这里判断一下完成没
        if (res.length !== errPromise.length && errPromise.length) {
            all(errPromise)
        }
    }).catch(err => {
        console.error(err, 'err')
    })
}
all([promiseError('A'), promiseRight('B'), promiseRight('c'), promiseError('D')]);

测试结果
[undefined, "B", "c", undefined] "eeeee"
["A", "D"] "eeeee"

@liuqiuzhen
Copy link

参考了网上的答案 并测试了其它几种情况
// Promise.all(task).then().catch() 会在所有task都resolve时才会进then方法,
// 并且把所有结果以一个数组返回。只要有一个失败,就会进catch。
// 但如果在单个请求中定义了catch方法,就不会进Promise.all的catch方法。
因此,可以在单个的catch中将失败的promise放入一个list,待一轮请求完成后,再去请求失败的请求。

    function http(value, flag) {
        return new Promise((r, j) => {
            
            setTimeout(() => {
                if (Math.random() < 0.5) { // 设定一个成功或者失败的条件
                    r(value)
                } else {
                    j(value)
                }
            }, Math.random() * 2000)

            // return new Promise((resolve, reject) => {
            //     setTimeout(() => {
            //         if (Math.random() < 0.5) { // 设定一个成功或者失败的条件
            //             resolve(value)
            //         } else {
            //             reject(value)
            //         }
            //     }, Math.random() * 2000)
            // }).then((val) => `{`
            //     console.log(flag ? '重新请求成功' : '第一次请求成功', value)
            //     r(val)
            // }, (rejVal) => { // 失败的请求,再次调用;
            //     console.log(flag ? '重新请求失败' : '第一次请求失败', value)
            //     r(http(rejVal, true))
            // })
    
        })
    }
    let A = http('A');
    let B = http('B');
    let C = http('C');
    let D = http('D');
    
    Promise.all([A, B, C, D]).then(res => {
        console.log('最终请求结果', res)
    }).catch((err)=>{
        console.log(err,'--')
    })

@BillScott1024
Copy link

BillScott1024 commented Mar 12, 2021

输出:
image

源码:

/**
 * Desc: Promise all 错误处理
 * Date: 2021-03-12
 * Author: Akimto
 * 异步请求通过 Promise.all 处理,怎么让其中失败的所有请求重试。

    Promise.all([A, B, C, D])
    4 个请求完成后发现 AD 请求失败了,如果让 AD 请求重试
 */

export class PromiseAll {
    private retryTimes: number = 3;


    /**
     * 模拟延迟
     * @param time 延迟时间 秒
     * @returns 
     */
    private sleep(time: time): Promise<any> {
        return new Promise<any>(resolve => {
            setTimeout(() => {
                resolve(null);
            }, time * 1000);
        });
    }

    private postRequest(param: string) {
        return new Promise(async resolve => {
            let retryTimes = this.retryTimes;
            const request = async (param: any) => {
                const requestDelay = Math.random() * 2;
                //模拟请求延迟和请求失败
                await this.sleep(requestDelay);
                let resMsg = ``;
                const isFailed = (param === "A" || param === "D");
                if (isFailed) {
                    resMsg = `请求:${param} 失败 重试次数: ${this.retryTimes - retryTimes} 耗时: ${requestDelay.toFixed(2)}ms`;
                    if (retryTimes > 0) {
                        retryTimes--;
                        console.log(`${param} retryTimes: ${retryTimes}`);
                        request(param);
                    } else {
                        resolve(resMsg);
                    }

                } else {
                    resMsg = `请求:${param} 成功 耗时: ${requestDelay.toFixed(2)}ms`;
                    resolve(resMsg);
                }
            }
            request(param);
        });
    }

    public async main() {
        console.log("main");
        const requestA = this.postRequest("A");
        const requestB = this.postRequest("B");
        const requestC = this.postRequest("C");
        const requestD = this.postRequest("D");

        await Promise.all([requestA, requestB, requestC, requestD]).then(result => {
            console.log(result);
        }).catch(error => {
            console.error(error);
        });

        console.log("finished");
    }

}

const promiseAll = new PromiseAll();
promiseAll.main();

在线运行:
Edit priceless-curran-hc8e1

@lucas270
Copy link

function request(type,time){
return new Promise((r,j)=>{
setTimeout(()=>{
if(Math.random()>0.5){
r(type)
}else{
r(request(type,time))
console.log('请求失败',type)
}

    },parseInt(time))
})

}

const A=request('A',Math.random()*1000);
const B=request('B',Math.random()*1000);
const C=request('C',Math.random()*1000);
const D=request('D',Math.random()*1000);

Promise.all([A,B,C,D]).then(res=>{
console.log('全部请求成功',res)
})

@weiChow
Copy link

weiChow commented Mar 12, 2021

let errorRequestType = [];

const http = (type) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(type);
      Math.ceil(Math.random() * 100) % 2 ? resolve() : reject();
    }, Math.ceil(Math.random() * 1000))
  }).catch(() => errorRequestType.push(type))
}

const requestAll = (requests) => {
  Promise.all(requests).then(() => {
    console.log('errorRequest.length:', errorRequestType.length);
    if (errorRequestType.length) {
      requestAll(errorRequestType.map(t => http(t)));
      errorRequestType = [];
    }
  });
}

requestAll([http('A'), http('B'), http('C'), http('D')])

@ByeLe
Copy link

ByeLe commented Mar 12, 2021

function request(data) {
    return new Promise((resolve, reject) => {
        const faile = Math.random() > 0.5 ? true : false; // 模拟失败
        setTimeout(() => {
            // console.log('faile----', faile);
            if (faile) {
                reject();
            } else {
                resolve({
                    success: true, 
                    detail : data,
                });
            }
        }, 1000);
    }).catch(() => {
        return {
            success: false,
            detail: data,
        }
    });
};
const detail = ['A', 'B', 'C', 'D'];
let list = [];
function handle(arr) {
    list = [];
    arr.forEach((item) => {
        list.push(request(item));
    });
    // console.log(list);
    Promise.all(list).then((data) => {
        let temp = [];
        // console.log(data);
        data.forEach((item) => {
            if (!item.success) {
                console.log(`${item.detail}请求失败,准备重新请求`);
                temp.push(item.detail);
            } else {
                console.log(`${item.detail}请求成功`);
            }
        })
        if (temp.length != 0) {
            // console.log('enter');
            handle(temp);
        }
    })  
}
handle(detail);

![Uploading image.png…]()

A请求失败,准备重新请求
B请求成功
C请求成功
D请求失败,准备重新请求
A请求成功
D请求失败,准备重新请求
D请求成功

@ByeLe
Copy link

ByeLe commented Mar 12, 2021

function request(data) {
    return new Promise((resolve, reject) => {
        const faile = Math.random() > 0.5 ? true : false; // 模拟失败
        setTimeout(() => {
            // console.log('faile----', faile);
            if (faile) {
                reject();
            } else {
                resolve({
                    success: true, 
                    detail : data,
                });
            }
        }, 1000);
    }).catch(() => {
        return {
            success: false,
            detail: data,
        }
    });
};
const detail = ['A', 'B', 'C', 'D'];
let list = [];
function handle(arr) {
    list = [];
    arr.forEach((item) => {
        list.push(request(item));
    });
    // console.log(list);
    Promise.all(list).then((data) => {
        let temp = [];
        // console.log(data);
        data.forEach((item) => {
            if (!item.success) {
                console.log(`${item.detail}请求失败,准备重新请求`);
                temp.push(item.detail);
            } else {
                console.log(`${item.detail}请求成功`);
            }
        })
        if (temp.length != 0) {
            // console.log('enter');
            handle(temp);
        }
    })  
}
handle(detail);

![Uploading image.png…]()

@docterlei
Copy link

const httpRequest = (type, time) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() * 1000 > time) {
        console.log(`请求${type}成功`);
        resolve;
      } else {
        console.log(`重新请求${type}`);
        reject({ type: type, time: time });
      }
    }, time);
  }).catch((err) => {
    httpRequest(err.type, err.time);
  });
};

const A = httpRequest("A", Math.random() * 1000);
const B = httpRequest("B", Math.random() * 1000);
const C = httpRequest("C", Math.random() * 1000);
const D = httpRequest("D", Math.random() * 1000);

Promise.all([A, B, C, D]).then((res) => {
  console.log(res);
});

@monadaa
Copy link

monadaa commented Mar 12, 2021

// 异步请求通过 Promise.all 处理,怎么让其中失败的所有请求重试。
        // Promise.all([A, B, C, D])
        // 4 个请求完成后发现 AD 请求失败了,如果让 AD 请求重试
        const fetchData = (url) => {
            let time = Math.random() * 1000;
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    if (Math.random() * 1000 > time) {
                        console.log(`${url}请求成功`);
                        resolve;
                    } else {
                        console.log(`${url}请求失败,重新请求`);
                        reject({ url: url });
                    }
                }, time);
            }).catch((err) => {
                fetchData(err.url);
            });
        };

        const fetchList = [fetchData("A"), fetchData("B"), fetchData("C"), fetchData("D")]

        Promise.all(fetchList).then((res) => {
            console.log(res);
        });

@owlsignl
Copy link

let num = 0;
        function pall(fn){
            return new Promise((resolve,reject)=>{
                fn(resolve,reject)
            }).then((result)=>{
                console.log(result)
                return Promise.resolve(result)
            }).catch((e)=>{
                console.log(e)
                return pall(fn)
            })
        }
        // 第一个promise
        const p1 = pall((resolve,reject)=>{
            setTimeout(()=>{
                resolve("这是p1的输入结果")
            },1000)
        })
        // 第二个promise
        const p2 = pall((resolve,reject)=>{
            num += 1;
            if(num > 4){
                setTimeout(()=>{
                    resolve("这是p2的输入结果")
                },1000) 
            }else{
                // 模拟失败请求
                setTimeout(()=>{
                    reject('这是请求出错的第' + num + '次')
                },1000)
            }
            
        })
        // 第三个promise
        const p3 = pall((resolve,reject)=>{
            setTimeout(()=>{
                resolve("这是p3的输入结果")
            },1000)
        })
        
        Promise.all([p1,p2,p3]).then((r)=>{
            console.log(r)
        }).catch((e)=>{
            console.log('还是出错',e)
        })

@ahaghosthao
Copy link

ahaghosthao commented Mar 12, 2021

/**
 * 题目 异步请求通过 Promise.all 处理,怎么让其中失败的所有请求重试
 * 本题的核心思想就是在 promise.catch 中捕获错误!
 */

const http = function(data){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            if(Math.random() <0.5){
                console.log(`${data} 第一次就请求成功啦~`);
                resolve(data);
            }else{
                reject(data);
                console.log(`${data} 第一次请求失败啦!!!!`)
            }
        },Math.random() * 1000)
    }).catch((rej)=>{
        http(rej);
    })
}

Promise.all([http('A'),http('B'),http('C'),http('D')]).then((res)=>{
    console.log('请求成功')
})

@muzishuiji
Copy link

muzishuiji commented Mar 13, 2021

代码: 
const requestA = function (reTry = true) {
  return new Promise((resolve, reject) => {
    throw Error("A");
  }).catch((err) => {
    if (reTry) {
      console.log("请求A失败重试");
      requestA(false);
    }
  });
};
const requestB = function (reTry = true) {
  return new Promise((resolve, reject) => {
    console.log("bbbb");
    resolve("B");
  }).catch((err) => {
    if (reTry) {
      console.log("请求B失败重试");
      requestB(false);
    }
  });
};
const requestC = function (reTry = true) {
  return new Promise((resolve, reject) => {
    console.log("cccc");
    resolve("C");
  }).catch((err) => {
    if (reTry) {
      console.log("请求C失败重试");
      requestC(false);
    }
  });
};
const requestD = function (reTry = true) {
  return new Promise((resolve, reject) => {
    throw Error("D");
  }).catch((err) => {
    if (reTry) {
      console.log("请求D失败重试");
      requestD(false);
    }
  });
};
Promise.all([requestA(), requestB(), requestC(), requestD()])
  .then(
    (res) => {
      console.log(res, "res----");
    },
    (err) => {
      console.log(err, "err----");
    }
  )
  .catch((err) => {
    console.log(err, "catch----");
  });


运行结果:

    bbbb
    cccc
    请求A失败重试
    请求D失败重试
    (4) [undefined, "B", "C", undefined] "res----"

@mingyuesun
Copy link

image

@liuestc
Copy link

liuestc commented Apr 10, 2021

思路:在catch里重试

function mockAsyncFn(arg) {
  return () => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (Math.random() < 0.5) {
          console.log(`success get ${arg}`);
          resolve(arg);
        } else {
          console.log(`request ${arg} err`);
          reject(arg);
        }
      }, Math.random() * 2000);
    });
  };
}

function retry(fn, maxRetry = 3) {
  return fn().catch((err) => {
    // console.log("maxRetry", maxRetry);
    if (--maxRetry > 0) {
      console.log(`request failed err ${maxRetry}`);
      return retry(fn, maxRetry);
    } else {
      return Promise.reject(e);
    }
  });
}

const result = ["A", "B", "C", "D"].map((item) => retry(mockAsyncFn(item)));

Promise.all(result)
  .then((res) => {
    console.log("res", res);
  })
  .catch((e) => {
    console.log("rej", e);
  });

@xiaocongWang
Copy link

// 基于 Promise 封装一个可指定重试次数的异步请求方法
async function request(name, retryNum = 1) {
    let result;

    for (let i = 0; i <= retryNum; i++) {
        try {
            // 是否进入重试
            const isRetry = i > 0;

            if (isRetry) {
                console.log(`重试${name}请求:第${i}次`);
            }

            // 这里是模拟异步请求
            result = await new Promise((resolve, reject) => {
                const random = Math.random();
                setTimeout(() => {
                    if (random < 0.2) {
                        reject(`${name}请求出错`);
                    } else {
                        if (isRetry) {
                            console.log(`${name}请求重试${i}次后成功`);
                        }
                        resolve(name);
                    }
                }, random * 2000);
            });
            // 如果请求成功,则跳出循环
            break;
        } catch(e) {
            // 最终将错误再抛出
            if (retryNum === i) {
                result = Promise.reject(e);
            }
        }
    }
    return result;
}

const p = Promise.all([request('A'), request('B'), request('C'), request('D')]);

p.then(result => console.log(result)).catch(e => console.log(e));

@wenhuiyang-luck
Copy link

function httpRequest(value, retry){
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() > 0.5) {
        resolve(value);
        console.log(value, retry ? '重新请求成功' : '第一次请求成功');
      } else {
        reject();
        console.log(value, retry ? '重新请求失败' : '第一次请求失败');
      }
    }, Math.random() * 1000);
  }).catch(() => {
    return httpRequest(value, true);
  });
}

const queue = [
  httpRequest('A'),
  httpRequest('B'),
  httpRequest('C'),
  httpRequest('D')
];

Promise.all(queue)
  .then(res => {
    console.log('成功',res)
  }).catch(err => {
    console.log('失败', err);
  })

@KieSun KieSun closed this as completed Sep 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests