6

I'm currently implementing a PDF viewer based on PDF.js and as part of that I learned about promise objects.

I also learned that runtime errors are not automatically shown in the debugging console:

PDFJS.getDocument(...).then(
  function(pdfDocument){
    alert(UndefinedVariable); // Not shown in console!
  },
  function(error){
    console.log("Error occurred", error);
  }
);

I haven't been able to find a pretty way to show runtime errors in the promise functions, other than adding .done() as described in http://www.asyncdev.net/2013/07/promises-errors-and-express-js/ (which doesn't work for PDF.js) or adding .catch(function(error){ console.error(error); }).

I know that I can break on exceptions from runtime errors in the debugger, but I also get breaks on other exceptions (in jQuery) by doing so, which means I have to step thorugh 5 jQuery exceptions on every page load, before I can even check if my own code contains runtime errors.

Is there any way to force the promise functions to log runtime errors like normal (without writing extra code for every function call)?

Woodgnome
  • 2,281
  • 5
  • 28
  • 52
  • What implementation of Promises are you using? Can you alter it? – Tibos Mar 11 '14 at 13:53
  • Not exactly sure what you are asking, but PDF.js defines the Promise object (`new Promise(...)`). It's in their core files, so I'd want to avoid altering that code if possible. – Woodgnome Mar 11 '14 at 14:02

2 Answers2

7

The problem you're experiencing is that an exception in the then callback does reject the promise returned by .then(), instead of calling the error handler that you passed in. That will only trigger for errors in the promise on which you called .then(). So you can chain your handlers:

PDFJS.getDocument(...).then(function(pdfDocument){
    alert(UndefinedVariable); // Now shown in console!
}).then(null, function(error){
    console.log("Error occurred", error);
});

Here, then(null, …) could also be abbreviated by catch(…).

If there is no done method that throws on errors, you could implement it yourself like this by throwing in a setTimeout.

Is there any way to force the promise functions to log runtime errors like normal (without writing extra code for every function call)?

No. That's just not how they were designed.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Sigh, that seems extremely stupid to me. Why break basic debugging functionality? – Woodgnome Mar 12 '14 at 09:11
  • @Woodgnome how would the sequential analogy look like? If you have a `catch {` clause with a `console.log` in it, you have to rethrow. – Benjamin Gruenbaum Mar 12 '14 at 10:10
  • @BenjaminGruenbaum: But how to write the analogy to not using a `try catch`? With promises, you have add something explicitly. – Bergi Mar 12 '14 at 12:31
  • @Bergi with `try/catch` you have to add something explicitly too, if you want to log and keep the exception propagating you need to `catch(e){` and then `throw e;` - just like you have to `.catch(function(e){` and then `throw e;` with promises. – Benjamin Gruenbaum Mar 12 '14 at 13:02
  • @BenjaminGruenbaum: No, when I omit the `try catch` then the exception will bubble and be logged automatically as unhandled… – Bergi Mar 12 '14 at 13:07
  • @Bergi exactly like promises. When you have an unhandled rejection it will propagate in the promise chain until it will be caught at some later point - if you use a good promise library (Like Bluebird or Q)- it will be logged automatically as unhandled too, if you don't it will be logged as unhandled when you terminate the chain with `.done`. – Benjamin Gruenbaum Mar 12 '14 at 13:12
1

In the Promise implementation, there is a try ... catch which takes an error from the callbacks and turns it into an error returned by the Promise.

One thing you can do is change that try...catch to log the errors before invoking the failure of the promise.

https://github.com/mozilla/pdf.js/blob/master/src/shared/util.js#L936

    } catch (ex) {
      console.error(ex); // <--- add this line
      nextStatus = STATUS_REJECTED;
      nextValue = ex;
    }

If native ECMAScript 6 promises are used instead, this trick probably won't work.

Tibos
  • 27,507
  • 4
  • 50
  • 64