質問

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?

役に立ちましたか?

解決

The first call of the chain is synchronous, so at first glance it seems unusual for exceptions raised in it to be then passed to $q to then call the error callbacks, which are for the asynchronous promise rejections (or indeed exceptions)

To quote from the $q docs

Q has many more features than $q

So the lack of fCall function sounds like one of the things the team decided could be removed. It looks like you do have to roll your own, like you have. You might want to use a technique like from https://gist.github.com/leon/8800809 to decorate $q with a fCall method, so you then use it like:

$q.fCall(f1).then(function()...

他のヒント

I know this is an older question, but I hit the same thing today and found this answer but didn't think I should need to add fCall() to get this to work. After a little digging I found this can be done in Angular v1.5 today (not sure at what point this became valid):

$q.when().then(() => f1)...
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top