😄 前言
try catch 可以说是学习编程第二课第三课这种基础中的基础的语句。更不用说我这种工作了将近三年,而且在学校老师就强调过很多遍,着实是惭愧,太水了。
很早就知道try catch,但是就是一直没有用在项目中,之前的团队都是小团队,且是创业公司,我这种菜鸟中的菜鸟都能当扛把子,一直都没有人来指导我,所有的开发规范规格都是我在网上东拼西凑的。开发经验都是一个个坑踩过来的。在此,为被我坑过的两家公司道歉,虽然它们给的工资也不高就是了🥺
现在公司项目用到了RN,在做的过程中有错误就闪退,而闪退就是一级BUG了,写的东西没有写web的时候那么随意。
一. try catch被动异常
1. 基础用法
try {
let a = 1
console.log(b)
} catch (err) {
// 会报错,b is not undefend
} finally {
// 不管怎么样都执行
}
在try 包括中的代码,如果出错的话,就不会继续执行try剩下的代码,而会直接跳到catch中,然后finally。
需要注意几点:
-
如果你在catch里面报错的话,就直接玩完了, 所以在catch中的语句块必须是可预知的!
-
不过try中的catch中也是可以无限嵌套,代码结构丑不说,好像没有什么意义
-
fianlly不管try中是否发生了错误,都是执行的
2. 关于finally,执行顺序:
try {
console.log(1)
console.log(b)
} catch (err) {
console.log(2)
} finally {
// 不管怎么样都执行
console.log(3)
}
上面的执行顺序是 1 -> 2 -> 3
try {
setTimout(() => {
console.log(b)
}, 0)
} catch (err) {
console.log(2)
} finally {
// 不管怎么样都执行
console.log(3)
}
console.log(5)
执行顺序是:3 -> 5 -> 报错
是的,在try中执行延时函数是会直接报错的,try catch的“被动技能”被禁。这个应该是由于在node宿主中的事件循环导致的,在一个执行栈中,微观事件肯定是先于宏观事件先执行的,在try catch中加上了setTimout微观事件的话,在执行的是,把该事件自动放入了待触发的队列中(先进先出),在等待try catch和下面的语句执行完毕之后,再次执行,而此时的运行时自然不存在try catch,所以不回抛出异常了。
🤔?而finally里面的语句和在下面的有什么差别呢?我能够想到的一种作用就是能够保证代码完整的结构
当然这个其实非常的重要。
二、try catch 主动异常
try {
let a = 2
if (a !== 1) {
throw 'a不等于1是不对的'
}
} catch (err) {
console.log(err) // a不等于1是不对的
}
主动抛出可以定义catch中的返回的参数。在代码没有语法错误的情况下,自己来判断是否应该进行异常的抛出。如果是if else 也是能够办到的,但是不够优雅,也不够装逼,毕竟整个功能模块中if else 已经够多的了。async await要解决的是promise回调地狱的问题。try catch主动抛出异常要解决是if else 逼格不够的问题(或许是这样😄)。
三、实际开发中的使用场景
第一次其实是使用在Vue过滤路由中使用来进行异常的判断。
// 路由处理中间件 - 原生判断
import auth from '@/assets/scripts/auth-middleware-copy' // -copy
const router = new Router(...)
router.beforeEach(async (to, from, next) => {
if (to.meta.title) {
document.title = to.meta.title
}
if (to.query.hasOwnProperty('ROOM_JID')) {
localStorage.setItem('ROOM_JID', to.query.ROOM_JID)
}
// 登录逻辑判断
if (to.path != '/author') {
await auth(to, from, next, router) // 非授权页面都经过/assets/scripts/auth-middleware-copy, 测试时可注释
}
next()
})
auto:
// ...
const fetchAccessToken = (roomid, openid) => {
const url = '/auth-api/wxAuth/gettoken'
return request.post(url, {roomid, openid})
}
export default async (to, from, next) => {
let tokey = to.query.tokey
// ...
try {
let remoteToken = await fetchAccessToken(queryRoomId, localOpenId)
if (remoteToken.expires_in < parseInt(new Date() * 1 / 1000)) { // 登录的失效过时了抛出异常,然后进入重新登录的逻辑
throw new Error('expire out')
}
// ...
// ...
} catch (error) {
console.log('token请求错误1', error)
Toast.fail({
message: '登录失败,发起授权',
duration: 1500
})
return restart(queryUid, queryRoomId)
}
}
四、其他
在写C的时候,似乎是在知乎听到一个人的留言:只有错误可预知时才用try, 所有不可预知的错误用try都是不负责任的写法。