相信在项目中为了维护代码,捕获错误,都是需要在项目中使用catch,今天就让我们来看看各种各样的catch写法,而且在前端领域内,异步问题是经常出现的,那Promise就应该熟记于心了,今天让我们一起来看看各种各样的Promise写法,你真的掌握了吗?
今天主打就是“我画你猜”,看看大家能够猜对多少?
try…catch…
首先来开胃菜, 如果觉得这里的很简单, 可以直接去后面看组合的demo
const getUserInfo = () => {
return new Promise((resolve, reject) => {
reject('error')
})
}
const getList = () => {
return new Promise((resolve, reject) => {
resolve('getList')
})
}
const mounted = async () => {
try {
const userInfo = await getUserInfo()
// 中断不再执行
const list = await getList(userInfo.id)
} catch (err) {
console.log(err) // 输出error(控制台未报错)
}
}
mounted()
这应该很符合流程和我们的想象,当前面接口出错时,下面的接口显然不能正常执行下去了,因为前面的接口请求,肯定是后面接口请求需要用到的请求参数,不然也不会让getUserInfo这个接口先请求,然后等待接口请求完成之后再进行其他请求.
如果没有try…catch会中断执行吗?如果没有try…catch会控制台报错吗?
如果分别用try…catch包裹两个请求,会怎么样?
如果Promise中有catch,那try…catch还能够捕获到吗?
如果Promise后有catch,没有try…catch会报错吗?
慢慢的,能够发现其实还有很多情况,需要我们慢慢发现,接下来一起来体验揭秘的感觉吧
第一个疑问,没有try…catch会中断执行
const getUserInfo = () => {
return new Promise((resolve, reject) => {
reject('error')
})
}
const getList = () => {
return new Promise((resolve, reject) => {
resolve('getList')
})
}
const mounted = async () => {
console.log(1)
const userInfo = await getUserInfo()
console.log(2)
const list = await getList()
console.log(3)
}
mounted()
只有输出了1,然后就中断执行,而且控制台出现报错
所以第一个疑问,也有了答案
为什么会报错,这里其实就是执行getUserInfo时,返回的reject中断了后面的逻辑
第二个疑问:
如果分别用try…catch包裹两个请求,会怎么样?
const getUserInfo = () => {
return new Promise((resolve, reject) => {
reject('error')
})
}
const getList = () => {
return new Promise((resolve, reject) => {
resolve('getList')
})
}
const mounted = async () => {
console.log(1)
try {
const userInfo = await getUserInfo()
} catch (err) {
console.log(err)
}
console.log(2)
try {
const list = await getList()
} catch (err) {
console.log(err)
}
console.log(3)
}
mounted()
整个mounted一直执行完毕,没有报错,但是输出了getUserInfo中的reject的值
原因就是getUserInfo中断了执行,但只中断包裹它最近的try…catch这个作用域,并且由最近的catch捕获到了错误。并不会影响mounted整个函数,getList所以正常执行
promise.catch
单个的try…catch就上面这些,接下来就是promise.catch与try…catch的组合了
疑问三
如果Promise中有catch,那try…catch还能够捕获到吗?
const getUserInfo = () => {
return new Promise((resolve, reject) => {
reject('error')
}).catch(err => {
console.log('getUserInfo', err)
})
}
const getList = () => {
return new Promise((resolve, reject) => {
resolve('getList')
}).catch(err=> {
console.log('getList', err)
})
}
const mounted = async () => {
console.log(1)
try {
const userInfo = await getUserInfo()
} catch (err) {
console.log('user catch', err)
}
console.log(2)
try {
const list = await getList()
} catch (err) {
console.log('list', err)
}
console.log(3)
}
mounted()
相信经过上面的例子,应该能猜到结果了,出现错误的地方,离最近的catch会抛出错误,其他流程一概不中断,不受影响
疑问四:
如果Promise中有catch,没有try…catch会报错吗?
const getUserInfo = () => {
return new Promise((resolve, reject) => {
reject('error')
}).catch(err => {
console.log('getUserInfo', err)
})
}
const getList = () => {
return new Promise((resolve, reject) => {
resolve('getList')
}).catch(err=> {
console.log('getList', err)
})
}
const mounted = async () => {
console.log(1)
const userInfo = await getUserInfo()
console.log(2)
const list = await getList()
console.log(3)
}
mounted()
到这里,大家就都应该能够回答出正确答案了
mounted函数全部执行
promise
当前面的promise已经reject,后面的then还会继续执行吗?
看下面的demo1
demo1
const p1 = new Promise((resolve, reject) => {
reject('p1 error')
})
p1.then((v) => {
console.info('p1 then1 resolve:', v)
}).then((v) => {
console.info('p1 then2:', v)
}).catch(e => {
console.info('p1 catch:', e)
})
直接输出了catch,前面的then都没有执行,因为没有捕获错误之前,抛出错误后面的执行会中断
demo2
const p1 = new Promise((resolve, reject) => {
reject('p1 error')
})
p1.then((v) => {
console.info('p1 then1 resolve:', v)
}, (e) => {
console.info('p1 then1 reject:', e) //输出
}).then((v) => {
console.info('p1 then2:', v) // 输出
}).catch(e => {
console.info('p1 catch:', e)
})
then中有两个参数,第一个参数回调能够拿到上一个promise的返回值,第二个参数,如果是回调能够取到上面promise捕获的错误,就相当于是catch,所以下面的没有再继续走catch的输出
then第二个参数有处理异常,就不会透传下一层
demo3
const p1 = new Promise((resolve, reject) => {
reject('p1 error')
})
p1.then((v) => {
console.info('p1 then1 resolve:', v)
}, (e) => {
console.info('p1 then1 reject:', e)
throw new Error('抛出异常')
}).then((v) => {
console.info('p1 then2:', v)
}).catch(e => {
console.info('p1 catch:', e)
})
then第二个参数处理异常后,再抛出新异常,会透传个下一层
这里throw new Error()与return Promise.reject(‘抛出异常’)效果一样,都是抛出错误,下面的p1 catch:会捕获到,不过两者的输出的内容还是不一样的,Error是一个错误对象,输出如上图,Promise.reject(‘抛出异常’)输出的是一个字符串,输出效果如下图
demo4
const p1 = new Promise((resolve, reject) => {
reject('p1 error')
})
p1.then((v) => {
console.info('p1 then1 resolve:', v)
}, (e) => {
console.info('p1 then1 reject:', e)
return 100
}).then((v) => {
console.info('p1 then2:', v)
}).catch(e => {
console.info('p1 catch:', e)
})
then第二个参数处理异常,同时返回resolve状态的数据,透传下一层的就是resolve状态了
promise+finally+return
如果觉得上面这两个知识点很简单,那也没关系,接着来哈,还要复杂情况
try …catch…后面存在finally,那finally的执行时机是怎么样的呢?
try …catch…中既有resolve又有return,则最后取的值是怎样的
demo1
var a = () => {
return new Promise((resolve, reject) => {
resolve('a resolve')
})
}
var b = async () => {
try {
var res = await a()
console.info('b await:', res)
Promise.resolve('b resolve')
return 'b return'
} catch (e) {
console.info('b e:', e)
return Promise.reject(e)
} finally {
console.info('b finally')
}
}
b()
.then((data) => {
console.info('b() data:', data)
})
.catch((e) => {
console.info('b() e:', e)
})
先看下结果,看看大家有没有猜对的
很明显,这里不会走到catch逻辑,但是这里有一个return和一个Promise.resolve
我们知道,async…await其实也是一个promise函数,所以b会返回一个promise;
promise后面then取到的是b返回的值,也就是有return的情况下,后面的then取到的是return的值;
如果没有return,则data就是undefined,注意,尽管Promise.resolve中有数据的,没有return的情况下,后面then拿到的数据是undefined,不是resolve中的值;
如果return Promise.resolve(‘b resolve’);这样的话,取到的b data: b resolve
如果a中返回的就是reject呢?看下面的例子
demo2
var a = () => {
return new Promise((resolve, reject) => {
// resolve('a resolve')
reject('a reject')
})
}
var b = async () => {
try {
var res = await a()
console.info('b await:', res)
return 'b resolve'
} catch (e) {
console.info('b e:', e) // 输出a reject
return Promise.reject(e) // 再次透传
} finally {
console.info('b finally')
}
}
b()
.then((data) => {
console.info('b() data:', data)
})
.catch((e) => {
console.info('b() e:', e) // 输出a reject
})
可以发现,无论b函数中是否走了try,都会执行finally
而错误想要层层传递,需要在catch中也return一个reject信息,这样在b.then后面才能继续捕获到错误了
如果在finally中还出现return呢?会出现怎样的情况,请接着看下面的例子
demo3
var a = () => {
return new Promise((resolve, reject) => {
// resolve('a resolve')
reject('a reject')
})
}
var b = async () => {
try {
var res = await a()
console.info('b await:', res)
return 'b resolve'
} catch (e) {
console.info('b e:', e)
return Promise.reject(e)
} finally {
console.info('finally')
return 'finally return'
}
}
b()
.then((data) => {
console.info('b() data:', data)
})
.catch((e) => {
console.info('b() e:', e)
})
普通猜测:b.catch–>finally->catch
但是想象很美好,现实不一样
我们发现:
1.最终已finally中的return为准
2.控制台报错了,因为b.catch未捕获到,但b.catch捕获的源头是a函数,所以控制台输出了a reject出错
可以看出,由于finally中还有return,所以覆盖了catch中的return,这样就导致了b.catch中的错误没有传递出来,所以控制台报错了
demo4
跟上面的demo小小变化,finally没有return,b.catch中也没有return,那b().then后面是怎么执行的呢?
var a = () => {
return new Promise((resolve, reject) => {
// resolve('a resolve')
reject('a reject')
})
}
var b = async () => {
try {
var res = await a()
console.info('b await:', res)
return 'b resolve'
} catch (e) {
console.info('b e:', e)
} finally {
console.info('b finally')
}
}
b()
.then((data) => {
console.info('b() data:', data)
})
.catch((e) => {
console.info('b() e:', e)
})
这又是很神奇的结果
因为会执行b().then()中会输出data为undefined
也就是说尽管b函数中走到了catch中,由于已经输出了a中的reject错误,这里返回默认是Promise.resolve()
demo5
接下来看a函数返回是resolve的情况
var a = () => {
return new Promise((resolve, reject) => {
resolve('a resolve')
})
}
var b = async () => {
try {
var res = await a()
console.info('b await:', res)
return 'b resolve'
} catch (e) {
console.info('b e:', e)
return Promise.reject(e)
} finally {
console.info('b finally')
return Promise.reject('finally return')
}
}
b()
.then((data) => {
console.info('b() data:', data)
})
.catch((e) => {
console.info('b() e:', e)
})
经过demo3, demo4,相信demo5大家就应该知道了
b.try输出,执行finally,由于finally中返回了reject,所以b.then进入了catch中
总结
1.reject错误,会由最近的catch捕获,在被最近的catch捕获之前,后面的流程会中断执行
2.finally是在then或者catch之后执行(不会晚于下一层对then或catch的捕获输出慢)
3.最终是什么返回给下一层,如果finally有return,它的优先级是高于且覆盖then或者catch的return的
4.如果finally没有return,就看then与catch里面的返回了,如果catch里面没有再return Promise.reject,那么catch默认return出去的是resolve的,值是undefined