Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS - Promises rethrow caught exceptions

In the following code, an exception is caught by the catch function of the $q promise:

// Fiddle - http://jsfiddle.net/EFpn8/6/
f1().then(function(data) {
        console.log("success 1: "+data)
        return f2();
    })
    .then(function(data) {console.log("success 2: "+data)})
    .catch(function(data) {console.log("error: "+data)});

function f1() {
    var deferred = $q.defer();
    // An exception thrown here is not caught in catch
    // throw "err";
    deferred.resolve("done f1");        
    return deferred.promise;
}

function f2() {
    var deferred = $q.defer();
    // An exception thrown here is handled properly
    throw "err";
    deferred.resolve("done f2");        
    return deferred.promise;
}  

However when I look in the console log output I see the following:

enter image description here

The exception was caught in Angular, but was also caught by the error handling of the browser. This behavior does reproduce with Q library.

Is it a bug? How can I truly catch an exception with $q?

like image 765
VitalyB Avatar asked Apr 27 '14 15:04

VitalyB


People also ask

How to catch rejected promise js?

catch " around the executor automatically catches the error and turns it into rejected promise. This happens not only in the executor function, but in its handlers as well. If we throw inside a . then handler, that means a rejected promise, so the control jumps to the nearest error handler.

Does catch return a promise?

The catch method is used for error handling in promise composition. Since it returns a Promise , it can be chained in the same way as its sister method, then() . catch() internally calls then() . This is observable if you wrap the methods.

Why we use$ q in AngularJS?

$q is integrated with the $rootScope. Scope Scope model observation mechanism in AngularJS, which means faster propagation of resolution or rejection into your models and avoiding unnecessary browser repaints, which would result in flickering UI.

What is q defer() in AngularJS?

$q. defer() allows you to create a promise object which you might want to return to the function that called your login function.


1 Answers

Angular's $q uses a convention where thrown errors are logged regardless of being caught. Instead, if you want to signal a rejection you need to return $q.reject(... as such:

function f2() {
    var deferred = $q.defer();
    // An exception thrown here is handled properly
    return $q.reject(new Error("err"));//throw "err";
    deferred.resolve("done f2");        
    return deferred.promise;
}  

This is to distinguish rejections from errors like SyntaxError. Personally, it's a design choice I disagree with but it's understandable since $q is tiny so you can't really build in a reliable unhandled rejection detection mechanism. In stronger libraries like Bluebird, this sort of thing is not required.

As a side note - never, ever throw strings : you miss on stack traces that way.

like image 147
Benjamin Gruenbaum Avatar answered Oct 04 '22 17:10

Benjamin Gruenbaum