使用第一级 try ... catch 捕获 JavaScript Promise 中的错误

IT技术 javascript node.js promise bluebird
2021-02-19 00:43:11

所以,我希望我的第一级捕获是处理错误的那个。反正有没有将我的错误传播到第一个捕获?

参考代码,不工作(还):

Promise = require('./framework/libraries/bluebird.js');

function promise() {
    var promise = new Promise(function(resolve, reject) {
        throw('Oh no!');
    });

    promise.catch(function(error) {
        throw(error);
    });
}

try {   
    promise();
}
// I WANT THIS CATCH TO CATCH THE ERROR THROWN IN THE PROMISE
catch(error) {
    console.log('Caught!', error);
}
5个回答

您不能使用 try-catch 语句来处理异步抛出的异常,因为函数在抛出任何异常之前已经“返回”。您应该改用promise.thenpromise.catch方法,它们表示 try-catch 语句的异步等效项。(或者使用@Edo 的回答中提到的 async/await 语法。)

您需要做的是返回Promise,然后将另一个链接.catch到它:

function promise() {
    var promise = new Promise(function(resolve, reject) {
        throw('Oh no!');
    });

    return promise.catch(function(error) {
        throw(error);
    });
}

promise().catch(function(error) {
    console.log('Caught!', error);
});

Promise 是可链接的,因此如果一个 Promise 重新抛出错误,它将被委托给下一个.catch.

顺便说一句,您不需要在throw语句周围使用括号throw a与 相同throw(a))。

对于它的value,您绝对应该在我的回答中使用该方法,而应该使用Promise。Promises 已经解决了这个问题并提供了 throw 安全。你可以简单地省略promise.catch,事实上,上面的整个代码都可以重构为Promise.reject("oh no")(尽管你应该总是拒绝错误)。然后你可以做Promise.reject("oh no").catch(function(e){ console.log(e); });which 日志“哦不”。除了可链接性和可组合性之外,Throw 安全性实际上是 promise 的最强卖点之一。
2021-04-21 00:43:11
@Kirk:只有在您无法编辑此promise功能时,我才会这样做,因为一次使用一个功能会更加一致。在这种情况下,我编辑了我的答案以添加指向可能解决方案的链接。
2021-05-03 00:43:11
@BenjaminGruenbaum:我假设这只是一个基于其他代码的模型示例,有时(重新)抛出错误,而不是这就是确切的代码。无论如何,我已经编辑了我的答案以更加强调使用promsies。
2021-05-08 00:43:11

使用新的async/await 语法,您可以实现这一点。请注意,在撰写本文时,并非所有浏览器都支持此功能,您可能需要使用babel(或类似的东西)来转译您的代码

// Because of the "async" keyword here, calling getSomeValue()
// will return a promise.
async function getSomeValue() {
  if (somethingIsNotOk) {
    throw new Error('uh oh');
  } else {
    return 'Yay!';
  }
}

async function() {
  try {
    // "await" will wait for the promise to resolve or reject
    // if it rejects, an error will be thrown, which you can
    // catch with a regular try/catch block
    const someValue = await getSomeValue();
    doSomethingWith(someValue);
  } catch (error) {
    console.error(error);
  }
}
如果函数返回 Promise,我们是否需要将该方法声明为异步方法。
2021-04-25 00:43:11
缺失:Promise.reject(err);在 catch 中声明stackoverflow.com/a/37993829/4933053
2021-05-08 00:43:11
@ItsmeJulian 这取决于你想如何处理它。如果您只想在 catch 中登录,那么您不需要冒泡错误。另外,throw err如果你想把它泡起来,我想我更喜欢内部捕获。
2021-05-09 00:43:11
如果要await在该函数中使用则只需要 async 关键字使用 async 关键字会产生一个副作用,即Promise将返回一个Promise。如果您想等待返回Promise的函数 X 的结果,则使函数 X 异步将无效。
2021-05-12 00:43:11

不!这是完全不可能的,因为 Promise 本质上是异步的。当抛出异常时,try-catch 子句将完成执行(时间旅行仍然不会被发明)。

取而代之的是,从所有函数中返回 promise,并在它们上挂一个错误处理程序。

我经常发现需要确保返回 Promise 并且几乎同样需要处理本地错误,然后有选择地重新抛出它。

function doSomeWork() {
  return Promise.try(function() {

    return request.get(url).then(function(response) {
      // ... do some specific work
    });

  }).catch(function(err) {
    console.log("Some specific work failed", err);
    throw err; // IMPORTANT! throw unless you intend to suppress the error
  });
}

这种技术(Promise.try/catch)的好处是您可以启动/确保 Promise 链,而没有解决/拒绝要求,这很容易被遗漏并造成调试噩梦。

为了扩展edo的答案,如果您想捕获不想等待的异步函数的错误。您可以在函数末尾添加 await 语句。

(async function() {
  try {
    const asyncResult = someAsyncAction();

    // "await" will wait for the promise to resolve or reject
    // if it rejects, an error will be thrown, which you can
    // catch with a regular try/catch block
    const someValue = await getSomeValue();
    doSomethingWith(someValue);

    await asyncResult;
  } catch (error) {
    console.error(error);
  }
})();

如果someAsyncAction失败,catch 语句将处理它。

我的意思是,如果某些代码正在await调用外部函数,则该代码仍然需要等待someAsyncAction才能完成。很多时候,人们可能想要触发一些异步操作,而不是等待解决/错误的Promise,例如发送分析数据。现在,当链接.catch(并await asyncResult完全省略)时,您仍然可以处理 上的异步错误someAsyncAction,同时确保没有其他逻辑在等待它。
2021-04-21 00:43:11
请注意:这仍将停止外部函数的完成,直到 asyncResult 完成(出现错误或成功)。如果你不想在asyncResult等待可言,一个链接.catchsomeAsyncAction()可能更容易。
2021-05-04 00:43:11
当您说它会停止外部函数的完成时,我不确定您的意思,但它不会阻止事件循环。正如它所写的那样,放置在外部函数之后的任何代码的执行都不会被函数内部Promise的解析所阻止。添加.catchto的唯一好处someAsyncAction()是错误处理将被同步绑定。UnhandledPromiseRejectionWarning如果在到达线路someAsyncAction之前拒绝这将避免无关的消息await asyncResult
2021-05-11 00:43:11