Try catch 的用法

2,080 阅读2分钟
try {
  // do some logic here.
} catch(ex) {
  handleException();
  throw exception;
}

Try Catch 是否越多越好?

不是。应该尽可能少。原因如下:

  • Try catch 会破坏代码的流畅。打断逻辑流,不美观。
  • 系统级一般对 exception 有统一的处理。比如打 log, 错误率统计等等。一旦 catch 了 log 又没有正确抛出的话,就没有统一的处理。
  • 所以应该尽可能的交给底层平台去处理 exception. 这样代码既美观,error 也能有统一的处理。而且也能让 app 及时在出错的地方停下来。

常见的错误:

  • 没有正确抛出 exception,导致 exception 丢失。(除非你知道自己在干什么,下面有腻子)。
try {
// some logic
} catch(ex) {
  console.log(ex);
}
  • 抛出 exception, 但是修改 exception 导致信息丢失。
try {
// some logic
} catch(ex) {
  throw new Error('There is some error occurs!');
}
  • 无意义的 catch
try {
// some logic
} catch(ex) {
  throw ex;
}

什么时候需要写 try catch? (假设系统级已经有比较完善的 exception 处理。)

  • 需要忽略出现的 exception。
function isJsonString(str) {
  try {
    JSON.parse(str);
    return true;
  } catch() { 
    return false;
  }
}
  • 需要细化 exception 或者 customize exception. (千万不要粗化 exception, 如上面 new Error 的例子)
function loadUser(id) {
  try {
    await userModel.get(id);
  } catch(ex) {
    throw new UnauthorizedError(`${}`); // (不太贴切,有没有更好的腻子)
  }
}

如何正确处理 catch 到的 exception? (上面多数都提到了,再总结一次)

  • 保证 exception 在底层已经处理。(如果没有,是时候写点更底层的代码了)
  • 永远不要吃掉 exception. 除非你知道自己在做什么。
  • 尽可能不要让 catch 到的 exception 表述的信息更加模糊,应该是更加精准。除非你知道自己在做什么。
  • 尽可能不要做无意义的 try catch, catch it and just throw it. 除非你知道自己要做什么。
  • 尽可能少写 try catch.
  • 尽可能让 catch 中的逻辑简单。如下面的例子,catch 中有复杂的操作,容易 throw exception. (不要把 try catch 当 if else 用)
function loadUser(id, email) {
  try {
    await userModel.getById(id);
  } catch(ex) {
    await userModel.getByEmail(email);
  }
}

什么时候应该 throw exception?

勇敢的 throw exception, 谨慎的 catch exception. 在方法设计中,应该尽可能用 throw 替代状态返回值。

// return true is saved return false if not saved
function saveUser(user) {
  // save user to database
}

True 和 False 是无法预见所有情况的,如果 return false, 我们无法知道到底出了什么错。 Catch exception not saved. No exception saved. 这样你也可以只关心正确的逻辑,如果没有 save 成功自动跳出。

JS 中有那哪些常见的坑?

最大的问题,JS 是异步的。

  • 永远无法 catch 到异步的 error.
try {
  setTimeout(()=> {
    throw new Error('Can you catch me?');
  }, 0);
} catch(ex) { 
// catch 不到 
}
function loadUser(id) {
  try {
    userModel.get(id);
  } catch(ex) { 
    // catch 不到
  }
}
try {
  users.forEach(async (user) => {
    await userModel.save(user);
  });
} catch(ex) {
  // catch 不到
}

总结成一句话就是:所有的异步操作都需要 await 以后才能 try catch。除非你知道,自己在做什么。