背景
在公司遇到了一个需求,后端在处理文件的时候前端采用轮询的方式来获取文件的状态,现在的问题是,如果后端处理的时间过长,前段用户等待时间过长,因此我们需要给用户一个弹窗来提示用户处理时间过长。
原代码
//定义获取函数
async function getMessage(info, times = 0) {
// 获取后端信息
let code = message.code;
try {
//code为1表示还在处理中
if (code == 1) {
await new Promise((resolve, reject) => {
//开启定时器进行轮询
setTimeout(async () => {
await getMessage(info, times + 1);
resolve()
}, 2000);
});
}
} catch (e) {
console.log('处理出错');
}
}
//执行代码
async function init(){
try{
await getMessage()
}catch(e){
console.log('外部接受错误');
}
}
init()
一代错误代码
一开始自己写,想通过reject进行终止,代码如下
async function getMessage(info, times = 0) {
// 获取后端信息
let code = message.code;
console.log('开始处理');
try {
//code为1表示还在处理中
if (code == 1) {
await new Promise((resolve, reject) => {
//开启定时器进行轮询
setTimeout(async () => {
//已经轮询100
if (times >= 5) {
reject("超时");
return;
}
await getMessage(info, times + 1);
resolve();
}, 2000);
})
}
} catch (e) {
console.log("处理出错");
throw '扔错'
}
}
async function init(){
try{
await getMessage()
}catch(e){
console.log('外部接受错误');
}
}
init()
/*
输出:
6 * 开始处理
处理错误
Uncaught (in promise) 扔错
*/
二代错误代码
这个代码仍然报错,报的依然是 Uncaught (in promise) 扔错
之后我们在处理出错那里打断点,发现确实有错误经过console.log(处理出错)
(真的踩了很久的坑
这时同事提醒,在Promise对象后面catch试试
async function getMessage(info, times = 0) {
// 获取后端信息
let code = message.code;
console.log('开始处理');
try {
//code为1表示还在处理中
if (code == 1) {
await new Promise((resolve, reject) => {
//开启定时器进行轮询
setTimeout(async () => {
//已经轮询100
if (times >= 5) {
reject("超时");
return;
}
await getMessage(info, times + 1);
resolve();
}, 2000);
}).catch(()=>{
throw 'PromiseCatch错误'
})
}
} catch (e) {
console.log("处理出错");
throw '扔错'
}
}
async function init(){
try{
await getMessage()
}catch(e){
console.log('外部接受错误');
}
}
init()
/*
输出:
6 * 开始处理
处理错误
Uncaught (in promise) 扔错
*/
最终代码
我们重新分析一下这个代码,首先从报错开始看,Uncaught (in promise)
,我们可以定位到,这一定是Promise的错误,其次再来看Promise
中的await
,它用来执行自己(请求函数),这个请求函数如果出错每次都会抛出一个错误,但是我们的Promise中并没有处理这个错误。因此Promise对象报错,所以我们应该为await包裹一个try catch,用于处理Promise返回的错误,并且reject掉,不能throw Error,详细可以看这篇文章 js中对于返回Promise对象的语句如何try catch
async function getMessage(info, times = 0) {
// 获取后端信息
let code = message.code;
console.log('开始处理');
try {
//code为1表示还在处理中
if (code == 1) {
await new Promise((resolve, reject) => {
//开启定时器进行轮询
setTimeout(async () => {
//已经轮询100
if (times >= 5) {
reject("超时");
return;
}
try{
await getMessage(info, times + 1);
}catch(e){
reject("超时")
}
resolve();
}, 2000);
}).catch(()=>{
throw 'PromiseCatch错误'
})
}
} catch (e) {
console.log("处理出错");
throw '扔错'
}
}
async function init(){
try{
await getMessage()
}catch(e){
console.log('外部接受错误');
}
}
init()
/*
6 开始处理
6 处理出错
外部接受错误
*/
后记
其实解决这个问题的方案也很多,我当时也考虑了另一种方案,就是通过添加返回值来判断,但被驳回了(也不算驳回?只是可能会改动比较多的地方,也不太保险,而且这个问题确实没有特别难)
Q.E.D.