promise中抛出的错误经常会遇见,下面探讨几种常见的出现promise的错误的情况,以及如何处理
- 当一个promise出现错误时,控制权将移交给最近的reject程序进行处理。
fetch('https://no-such-server.blabla') // reject
.then(response => response.json())
.catch(err => alert(err)) // TypeError: Failed to fetch(这里的文字可能有所不同)
这里当无法解析数据报错时,首先catch回调先执行捕获错误。
- promise 的执行者(executor)和 promise 的处理程序周围有一个“隐式的
try..catch”。当主动抛出错误时,后面的catch会捕获到。
new Promise((resolve,reject)=>{
throw new Error('error')
}).catch((err)=>{
console.log(err);
})
上述代码类似于下面:
new Promise((resolve,reject)=>{
reject(new Error('error'))
}).catch((err)=>{
console.log(err);
})
无论是否主动reject 只要throw抛出错误,都会被下面的catch捕获到。
对于所有的 error 都会发生这种情况,而不仅仅是由 throw 语句导致的这些 error。例如,一个编程错误:
new Promise((resolve, reject) => {
resolve('ok')
}).then((res) => {
test() // 此處不存在這個函數
}).catch((err) => {
console.log(err);
})
也会被错误捕获。
- 再次抛出错误
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(function(error) {
alert("The error is handled, continue normally");
}).then(() => alert("Next successful handler runs"));
注意: 此时执行到catch之后 仍然会继续执行then回调。除非在catch 里面主动抛出throw错误,那么then回调就不会被执行,错误继续由下一个catch捕获。promise链继续向下执行。
例子:
// 执行流:catch -> catch-> then
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(function (error) {
alert("The error is handled, continue normally");
throw new Error('fff')
}).then(() => {
// 這裡不會被執行
alert("Next successful handler runs")
}).catch((err) => {
alert(err)
}).then(() => {
console.log('end');
});
执行结果为:
- The error is handled, continue normally
- fff
- end
catch 后面有then 则会继续执行,catch后面没有then 则执行到catch为止。
- promise链中未处理的错误
new Promise((resolve,reject)=>{
// resolve('ggg')
reject('hhhhhhhhh')
}).catch(()=>{
console.log('yyyyyyyyyyy')
}).then(()=>{
console.log('iiiiiiiiiiiiiii')
})
catch后面没有then 执行到catch为止
new Promise((resolve,reject)=>{
// resolve('ggg')
reject('hhhhhhhhh')
}).then(()=>{
console.log('iiiiiiiiiiiiiii')
}).catch(()=>{
console.log('yyyyyyyyyyy')
})
window.addEventListener('unhandledrejection', function(event) {
// 这个事件对象有两个特殊的属性:
alert(event.promise); // [object Promise] —— 生成该全局 error 的 promise
alert(event.reason); // Error: Whoops! —— 未处理的 error 对象
});
new Promise(function() {
throw new Error("Whoops!");
}); // 没有用来处理 error 的 catch
对于promise链中没有处理的错误,一般可以全局监听unhandledrejection事件,来捕获错误。
- promise链代码周围有个隐式的
try..catch,所以所有的同步代码都可以得到处理。但是对于异步代码的话就没办法处理了。
new Promise(function(resolve, reject) {
setTimeout(() => {
throw new Error("Whoops!");
}, 1000);
}).catch(alert);
这里由于setTimeout是个异步任务里面的宏任务,因此里面抛出去的错误无法被隐式的try catch 捕获到。因此无法被处理,所以在catch函数里面就无法被执行到。
7 async await 实现异步操作
主要用来简化promise链 使异步操作看起来像同步操作 一般使用try catch 来捕获异步操作
const sleep = () => new Promise((resolve)=>{
setTimeout(resolve, 1000);
})
const exection = async ()=>{
try {
await sleep()
} catch (error) {
throw new Error(error)
}
}
exection()
但其实await本身也可以实现捕获错误 catch 链实现
const sleep = () => new Promise((resolve)=>{
setTimeout(resolve, 1000);
})
const exection = async ()=>{
// try {
// await sleep()
// } catch (error) {
// throw new Error(error)
// }
const res = await sleep().catch((error)=>{
throw new Error(error)
})
console.log(res)
}
exection()
这里如果sleep 出现错误的话 错误将会由catch捕获 如果正常的话 res 可以拿到正常的值。
如果使用then 继续取值的话 res 将会取不到值 由then 取值
const sleep = () => new Promise((resolve)=>{
setTimeout(()=>{
resolve('success')
}, 1000);
})
const exection = async ()=>{
// try {
// await sleep()
// } catch (error) {
// throw new Error(error)
// }
const res = await sleep().catch((error)=>{
throw new Error(error)
}).then((res)=>{
console.log(res) // 这里success
})
console.log(res) // 这里undefined 取不到值
}
exection()