在实际项目中使用try catch

661 阅读4分钟

😄 前言

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都是不负责任的写法。