最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript Exceptions are hidden in Promises. How can I display them without catch? - Stack Overflow

programmeradmin4浏览0评论

Edit:

Promises do not hide exceptions, as was pointed out by the excellent (accepted) answer. I want to elaborate on how exceptions in promises were invisible:

I was working on a project that used a propriatary library to make ajax calls. Now in case something in the callback of the ajax-call went wrong an exception would be thrown. This exception would then trigger the reject() to be called, which was then silently discarded. In fact the exceptions were not hidden, but actively disposed of further down the code in an empty error-callback. This ultimatly led to a situation where it was very difficult to even recognize that an error had occured.


Here the original question:

I know that I can add a catch-block to all my promises and console.log the error there. In my usecase I need to catch the exceptions at a higher level up the call-stack.

/

Here in another question on SO, the accepted answer also proposes catch-blocks:

Catching errors generated in Promises within Promises in JavaScript

Edit:

Promises do not hide exceptions, as was pointed out by the excellent (accepted) answer. I want to elaborate on how exceptions in promises were invisible:

I was working on a project that used a propriatary library to make ajax calls. Now in case something in the callback of the ajax-call went wrong an exception would be thrown. This exception would then trigger the reject() to be called, which was then silently discarded. In fact the exceptions were not hidden, but actively disposed of further down the code in an empty error-callback. This ultimatly led to a situation where it was very difficult to even recognize that an error had occured.


Here the original question:

I know that I can add a catch-block to all my promises and console.log the error there. In my usecase I need to catch the exceptions at a higher level up the call-stack.

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

Here in another question on SO, the accepted answer also proposes catch-blocks:

Catching errors generated in Promises within Promises in JavaScript

Share Improve this question edited Oct 1, 2017 at 17:56 Tobias Gassmann asked Oct 1, 2017 at 11:41 Tobias GassmannTobias Gassmann 11.9k18 gold badges61 silver badges96 bronze badges 2
  • 2 That article you read is over two years old. Promises are in no way silently swallowing exceptions any more. – Bergi Commented Oct 1, 2017 at 12:13
  • 1 Yes, you definitely should .catch() and handle any errors in your asynchronous programs. – Bergi Commented Oct 1, 2017 at 12:15
Add a ment  | 

2 Answers 2

Reset to default 9

Javascript silently swallows Exceptions that are thrown within a Promise.

No, it doesn't. An exception thrown in a promise executor (the function you pass new Promise) or a then/catch handler is used as the value of the rejection of the promise. Any decent implementation will also log a console error if you have unhandled rejections. For instance, try this in a recent version of Chrome or Firefox:

new Promise(() => { throw new Error("Unhandled"); })

In the console you'll find:

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

Soon, NodeJS will start terminating the process on unhandled rejections just like unhandled exceptions. Because rejections are exceptions.

I do not want to add a catch-block to all my promises.

You don't have to. The rule of promises is you either return the promise or handle rejections from it; almost never both. (You'd do both only rarely, such as when you're "wrapping" the error that occurred to make it more high-level.) So you only need a catch on promises that you don't propagate to the caller. Best practice is to propagate to the highest level you can and then handle them there. Most of the time you don't write a catch because you're propagating the promise.

Can I monkey-patch (or else) the native Promises in such a way that they stop hiding my exceptions?

Well, again, they don't. You can replace Promise and Promise.prototype.then so they report exceptions to the console, but you'll end up reporting things that are handled by subsequent handlers and shouldn't be reported. For example:

// 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!");
});

...but it wouldn't be a good idea, as you can see.

If you follow the propagate-or-handle rule, you should be fine with built-in promises.


It's also probably worth noting async/await syntax, which are new as of ES2017: When using async/await, promise rejection values are used as exceptions, closing the circle:

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

In browsers, you can listen to the unhandledrejection event that is emitted for uncaught rejected promises:

window.addEventListener('unhandledrejection', function(event) {
  event.preventDefault();

  // the reject value is available as event.reason
  console.error("Promise was rejected with reason:", event.reason);
});


Promise.reject("something");

This applies both to native promises and some Promise libraries (such as Bluebird).

发布评论

评论列表(0)

  1. 暂无评论