首页 > 解决方案 > Catch 块包装了一个在未执行的 setTimeout 内抛出的函数

问题描述

最近经历了一些奇怪的事情,没有一个 catch 块被执行:

function funcWillThrow() {
  try {
    setTimeout(() => {
      throw "Has thrown";
    }, 3000);
  } catch (error) {
    console.log(error)
  }
}

function caller() {
  funcWillThrow();
}

caller();

function funcWillThrow() {
    setTimeout(() => {
      throw "Has thrown";
    }, 3000);
}

function caller() {
  funcWillThrow();
}

try {
  caller();
} catch (error) {
  console.log(error);
}

根据mdn 文档

当前函数的执行将停止(throw 之后的语句不会被执行),控制权将传递给调用堆栈中的第一个 catch 块。如果调用函数之间不存在 catch 块,则程序将终止。

我的猜测是调用堆栈发生了一些事情,如文档中所述。关于可能发生的事情的任何想法。

标签: javascriptfunctiontry-catch

解决方案


setTimeout稍后(在您的特定代码中 3 秒后)调用提供的函数,到那时调用的函数setTimeout早已终止。

要在以后的函数中捕获异常,请将错误处理放在该函数中:

function funcWillThrow() {
  setTimeout(() => {
    try {
      throw "Has thrown";
    } catch (error) {
      console.log(error);
    }
  }, 3000);
}

根据您在下面的评论,您可能正在寻找 Promises。由于该操作是异步的,并且发生在调用它的堆栈之外,因此为了捕获该堆栈中的错误,您需要等待该操作。理想情况下,您会利用reject. Promise像这样的东西:

function funcWillThrow() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("Has thrown");
    }, 3000);
  });
}

(async () => {
  try {
    await funcWillThrow();
  } catch (err) {
    console.log(err);
  }
})();

如果您特别需要能够从回调中抛出setTimeout,您也需要在那里捕获:

function funcWillThrow() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        throw "Has thrown";
      } catch (error) {
        reject(error);
      }
    }, 3000);
  });
}

(async () => {
  try {
    await funcWillThrow();
  } catch (err) {
    console.log(err);
  }
})();

或者setTimeout将自身自定义为 aPromise并使用正常的错误处理:

function myTimeout(ms) {
  return new Promise(function(resolve) {
    setTimeout(resolve, ms);
  });
}

(async () => {
  try {
    await myTimeout(3000).then(() => {
      throw "Has thrown";
    });
  } catch (err) {
    console.log(err);
  }
})();


推荐阅读