Javascript异常隐藏在Promises中.如何在没有捕获的情况下显示它们?

Tob*_*ann 1 javascript exception promise es6-promise

编辑:

承诺不会隐藏异常,正如优秀(接受)的答案所指出的那样.我想详细说明承诺中的例外是如何不可见的:

我正在研究一个使用专有库来进行ajax调用的项目.现在,如果ajax-call回调中的某些内容出错,则会抛出异常.然后,此异常将触发reject()被调用,然后以静默方式丢弃.实际上,异常并未隐藏,而是在空错误回调中进一步向下处理代码.这最终导致甚至很难识别出错误的情况.


原来的问题是:

我知道我可以在我的所有承诺中添加一个catch-block,并在那里添加console.log错误.在我的用例中,我需要在调用堆栈的更高级别捕获异常.

http://jamesknelson.com/are-es6-promises-swallowing-your-errors/

在另一个关于SO的问题中,接受的答案还提出了阻塞:

捕获JavaScript中的Promises中的Promises中生成的错误

T.J*_*der 8

Javascript默默地吞下Promise中抛出的异常.

不,它没有.在promise执行器(您传递的函数new Promise)或then/ catchhandler中抛出的异常用作拒绝承诺的值.如果您有未处理的拒绝,任何体面的实现也会记录控制台错误.例如,请在最新版本的Chrome或Firefox中试用:

new Promise(() => { throw new Error("Unhandled"); })
Run Code Online (Sandbox Code Playgroud)

在控制台中,您会发现:

Uncaught (in promise) Error: Unhandled
    at Promise (js:13)
    at new Promise ()
    at js:13

很快,NodeJS将开始终止未处理拒绝的过程,就像未处理的异常一样.因为拒绝例外.

我不想在我的所有承诺中添加一个捕获块.

你不必.承诺的规则是你要么退还承诺,要么处理拒绝; 几乎从来没有.(你很少做到这两点,例如当你"包装"发生的错误以使其更高级别时.)所以你只需要一个catch不会传播给调用者的承诺.最佳做法是尽可能地传播到最高级别,然后在那里处理它们.大多数时候你不写一个catch因为你正在宣传这个承诺.

我是否可以通过这种方式对本机Promise进行修补(或其他方式),以防止我的异常隐藏?

好吧,他们再也没有.您可以替换PromisePromise.prototype.then让他们报告异常到控制台,但你最终会报告说,在事情处理的后续处理程序,不应该报道.例如:

// NOT RECOMMENDED
const RealPromise = Promise;
Promise = class Promise extends RealPromise {
  constructor(executor) {
    super((resolve, reject) => {
      try {
        executor(resolve, reject);
      } catch (e) {
        console.error(e);
        reject(e);
      }
    });
  }
  
  then(onResolved, onRejected) {
    return super.then(val => {
      try {
        return onResolved(val);
      } catch (e) {
        console.error(e);
        throw e;
      }
    }, onRejected);
  }
};

new Promise(() => {
  throw new Error("Handled");
}).catch(e => {
  console.log("But I handled it!");
});
Run Code Online (Sandbox Code Playgroud)

......但是你可以看到,这不是一个好主意.

如果你遵循传播或处理规则,你应该没有内置的承诺.


它也可能值得注意async/ await语法,从ES2017开始是新的:当使用async/时await,promise promise被用作异常,关闭圆圈:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 500, "Failed");
  });
}
(async () => {
  try {
    await foo();
  } catch (e) {
    console.log("Got error: ", e);
  }
})();
Run Code Online (Sandbox Code Playgroud)