Consider the following code:
// Fiddle - http://jsfiddle.net/EFpn8/3/
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;
}
If the following code runs with an exception in f2, then the catch function is called correctly. However, in case there is an exception in f1 then the catch code never executes and only a standard JS exception occurs.
In the original Q library, this could be handled by this code:
// Fiddle - http://jsfiddle.net/FEPc7/
Q.fcall(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)});
Using fcall the f1 function is safely guarded and an exception in it will trigger the catch function as expected.
Since it seems to be that the same behavior from all members of a promise chain would be helpful and natural to the developer, I made the following function for AngularJS:
// Fiddle - http://jsfiddle.net/EFpn8/5/
function promise(work) {
var deferred = $q.defer();
try {
deferred.resolve(work());
} catch(err) {
deferred.reject(err);
throw err;
}
return deferred.promise;
}
Which can be used like so:
promise(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)});
This works fine, however, it seems rather a hack. Is there something inherit in Angular to do that instead? Or is it unnecessary for some reason?