异常处理
一、认识
Promise
的异常穿透机制: return new Promise(()=>{})
以及 Promise.then(()=>{})
回调函数内部发生的错误具有 冒泡 的性质, 会一直向后传递,直到被捕获为止。也就是说: 错误总是被下一个 catch
语句捕获。因此, Promise
的异常穿透有以下特点:
-
Promise
回调函数内部任何操作出现问题, 不会传递到外层代码, 不会退出进程, 不会中断外部程序执行 -
Promise
失败回调 获取不到自身 成功回调 抛出的错误, 因此, 我们可以在最后指定失败的回调 -
前面任何操作出现了异常, 都会直接传递到最后失败的回调中进行处理。会跳过 抛出错误 到 失败回调 的中间环节。
-
在失败的回调处理完成后, 返回的还是
Promise
, 因此可以在失败的回调后继续.then
或者.catch
。
二、吃掉错误
如果没有使用 .then(()=>{},()=>{})
或者 .then(()=>{}).catch(()=>{})
指定错误处理的回调函数, return new Promise(()=>{})
以及 Promise.then(()=>{})
抛出的错误不会传递到外层代码,即不会有任何反应。 也就是说即使 return new Promise(()=>{})
以及 Promise.then(()=>{})
回调函数内部抛出错误, 不会退出进程, 中断程序执行。通俗的说法就是 Promise
会吃掉错误。
console.log("失败之前");
new Promise((resolve) => {
throw new Error("失败");
})
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
console.log(4);
});
console.log("失败之后");
三、自身错误
Promise
的错误总是被下一个 catch
语句捕获。因此, Promise
失败回调 获取不到自身 成功回调 抛出的错误, 因此, 我们可以在最后指定失败的回调。
3.1 .then(()=>,()=>)
.then(()=>{},()=>{})
可以捕获之前 then
或者 new Promise(()=>{})
中抛出的错误
return new Promise((resolve) => {
resolve();
})
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
throw new Error("失败");
})
.then(
() => {
console.log(3);
},
(error) => {
console.log("3 error", error);
}
);
.then(()=>{},()=>{})
捕获不到自身 resolved
回调抛出的错误
return new Promise((resolve) => {
resolve();
})
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(
() => {
console.log(3);
throw new Error("失败");
},
(error) => {
console.log("3 error", error);
}
);
这是因为 Promise
的错误穿透机制: 自身抛出的错误会一直向后传递, 总是被下一个 .then(()=>{},()=>{})
或者 .catch()
函数捕获。
3.2 .then(()=>).catch(()=>)
一般来说,不要在then()
方法里面定义 Reject
状态的回调函数(即then
的第二个参数),总是使用catch
方法。.then(()=>{}).catch(()=>{})
写法可以捕获前面then
方法执行中的错误,也更接近同步的写法(try/catch
)。因此,建议总是使用catch()
方法,而不使用then()
方法的第二个参数。
四、错误越级
Promise
前面任何操作包括(return new Promise(()=>{})
以及 Promise.then(()=>{},()=>{})
回调函数内部)出现了异常, 都会直接传递到最后失败的回调 包括(.then(()=>{},()=>{ 处理失败 })
以及 .then().catch(()=>{})
)中进行处理, 会跳过 抛出错误 到 失败回调 的中间环节。
4.1 new Promie then then
new Promise((resolve) => {
throw new Error("失败");
})
.then(() => {
console.log(1); // 不执行
})
.then(() => {
console.log(2); // 不执行
});
4.2 new Promise then then rejectCallback or catch
new Promise then then catch
new Promise((resolve) => {
throw new Error("失败");
})
.then(() => {
console.log(1); // 不执行
})
.then(() => {
console.log(2); // 不执行
})
.catch((error) => {
console.log("catch error", error);
});
new Promise then then rejectCallback
new Promise((resolve) => {
throw new Error("失败");
})
.then(() => {
console.log(1); // 不执行
})
.then(
() => {
console.log(2); // 不执行
},
(error) => {
console.log("rejectCallback", error);
}
);
4.3 new Promise then then rejectCallback or catch then
new Promise then then catch then
new Promise((resolve) => {
throw new Error("失败");
})
.then(() => {
console.log(1); // 不执行
})
.then(() => {
console.log(2); // 不执行
})
.catch((error) => {
console.log("catch error", error);
})
.then(() => {
console.log(3); // 3
});
new Promise then then rejectCallback then
new Promise((resolve) => {
throw new Error("失败");
})
.then(() => {
console.log(1); // 不执行
})
.then(
() => {
console.log(2); // 不执行
},
(error) => {
console.log("rejectCallback", error);
}
)
.then(() => {
console.log(3); // 3
});
五、错误链式
Promise
在失败的回调处理完成后, 返回的还是 Promise
, 因此可以在失败的回调后继续 .then
或者 .catch
。