资讯专栏INFORMATION COLUMN

警示后人系列:为什么我没有catch到回调函数中抛出的错误?

fnngj / 789人阅读

摘要:回调函数的栈帧被放入时,执行栈是空的。总结用语句包裹回调函数的定义,无法捕获到回调函数中的错误。如果回调函数运行时没有外层函数,你必须在回调函数内部做错误的捕获和处理。

今天犯了一个js中的错误,记录一下警示后人:)

事情是这样,koa会帮我们捕获中间件中抛出的错误,从而不让服务器崩溃,如下图:

服务器为此次请求返回500,仍然能够处理后续的请求。

从这一点出发,我就认为,我可以在中间件里面随便throw,这样koa就能在控制台帮我打印出所有错误的信息,反正也不会对后续请求造成影响。

但是今天的错误是这样的:

进程居然崩溃了!这样上线岂不是要出事?

为什么koa这回没有捕获到我throw的错误呢?

用简单的代码模拟一下这个场景:

try {
  setTimeout(() => {
    try {
      throw 500;
    } catch (err) {
      console.log("err1", err);  // called
      throw err;
    }
  }, 0);
} catch (err) {
  console.log("err2", err)  // never called
}


可以看出,内层的try确实捕获到了错误,但是当我们把这个错误继续抛出,外层的try却没有捕获到这个错误

原因在于,回调函数被异步调用时,外层try中的代码其实已经执行完了,栈帧已经从执行栈中弹出。回调函数的栈帧被放入时,执行栈是空的

错误被抛出后,沿着执行栈,希望找到“外层”函数的try...catch语句。可是这个回调函数根本就没有“外层”函数了,因此这是一个没有被捕获到的错误,这会造成进程的崩溃。

总结

用try语句包裹回调函数的定义,无法捕获到回调函数中的错误。必须用try语句包裹运行时的外层函数。如果回调函数运行时没有外层函数,你必须在回调函数内部做错误的捕获和处理。

如果回调函数定义在Promise中,你可以直接在回调函数中调用reject(reason),让这个Promise的订阅者来处理错误:

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    try {
      throw 500;
    } catch (err) {
      console.log("err1", err);  // called
      reject(err);
    }
  }, 0);
});

p.catch(err => {
  console.log("err3", err);  // called
});

如果回调函数由async function的await关键字来执行,那么可以通过reject Promise,让async function中的try...catch捕获到错误。

async function fun() {
  try {
    await new Promise((resolve, reject) => {
      setTimeout(() => {
        try {
          throw 500;
        } catch (err) {
          console.log("err1", err);  // called
          reject(err);
        }
      }, 0);
    });
  } catch (err) {
    console.log("err4", err);  // called
    throw err;
  }
}
try {
  fun();
} catch (err) {
  console.log("err5", err);  // not called
}

注意try {fun();}无法捕获到错误,因为这个函数不是通过await来执行的。错误抛出的时候,这个try语句早已经执行完。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93302.html

相关文章

  • Node 错误处理之挖坑系列

    摘要:一中的对象包含了错误的具体信息,包括错误堆栈等。不源码了,特别简单,自己去一下。 一. Error     JS 中的 Error 对象. 包含了错误的具体信息,包括 name、message、错误堆栈 stack 等。可以以 new Error 方式创建实例抛出,或调用 Error.captureStackTrace 为已有对象添加 stack 错误堆栈信息 而后抛出showImg(...

    afishhhhh 评论0 收藏0
  • 解析 Promise 原理,实现一个Promise

    摘要:解析原理,实现一个概述这篇文章旨在解析的异步实现原理,并且以中的为蓝本实现一个简单的。具体的规范可以参见细节构造器中必须传入函数,否则会抛出错误。中的回调返回值会影响返回的对象。执行器传入构造器的为函数,并且在构造时就会执行。 解析 Promise 原理,实现一个Promise 概述 这篇文章旨在解析 Promise的异步实现原理,并且以 ES6中的 Promise 为蓝本实现一个简单...

    silenceboy 评论0 收藏0
  • JavaScript的异常处理

    摘要:主要用于捕捉异常。这包括在块里抛出的异常。并且同时捕获到一些关于异常的信息。秒后输出统一异常处理代码中抛出的异常,一种是要展示给用户,一种是展示给开发者。 当 JavaScript 引擎执行 JavaScript 代码时,有可能会发生各种异常,例如是语法异常,语言中缺少的功能,由于来自服务器或用户的异常输出而导致的异常。 而 Javascript 引擎是单线程的,因此一旦遇到异常,Ja...

    PrototypeZ 评论0 收藏0
  • 对JavaScript中的异步函数进行异常处理及测试

    摘要:总结最后总结一下从异步函数抛出的错误不会是普通的异常。异步函数和异步方法总是返回一个,无论是已解决还是被拒绝。要拦截异步函数中的异常,必须使用。 翻译:疯狂的技术宅原文:https://www.valentinog.com/bl... 本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章 可以在 Javascript 的异步函数中抛出错误吗...

    bigdevil_s 评论0 收藏0
  • 对JavaScript中的异步函数进行异常处理及测试

    摘要:总结最后总结一下从异步函数抛出的错误不会是普通的异常。异步函数和异步方法总是返回一个,无论是已解决还是被拒绝。要拦截异步函数中的异常,必须使用。 翻译:疯狂的技术宅原文:https://www.valentinog.com/bl... 本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章 可以在 Javascript 的异步函数中抛出错误吗...

    paulli3 评论0 收藏0

发表评论

0条评论

fnngj

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<