Angular conditional promises
Asked Answered
B

2

6

For an angular project, I have to nest promises and I run into cases where I am not sure of what I am doing. Here is one of my code :

return Action1().then(function (data) {
    var defer = $q.defer();
    if (data.condition) {
        $q.all([Action2(), Action3(), Action4()]).then(function () {
            defer.resolve();
        });
    } else {
        defer.reject("error_code");
    }
    return defer.promise;
});

Action1, Action2, Action3 and Action4 are working promises functions. It's a lot of promises and actions depend on conditions. Can I do that and be sure my main function will be always resolved or rejected?

I read that we can pass promise inside resolve function. Can I do that and is this the same as above:

return Action1().then(function (data) {
    var defer = $q.defer();
    if (data.condition) {
        defer.resolve($q.all([Action2(), Action3(), Action4()]);
    } else {
        defer.reject("error_code");
    }
    return defer.promise;
});
Banister answered 16/4, 2015 at 10:29 Comment(0)
L
3

No, it is not. Your first function would stay forever pending if one of Action2(), Action3() or Action4() did "throw", and reject the $q.all(…) promise - your deferred is never resolved then. This is the most common bug of the deferred antipattern you've used here.

Your second function does mitigate this, but is still unncessary complicated. You don't need a deferred here at all! Just return the promise directly, and use $q.reject:

return Action1().then(function (data) {
    if (data.condition) {
        return $q.all([Action2(), Action3(), Action4()]);
    } else {
        return $q.reject("error_code");
    }
});

Or, as this happens inside a then handler, you can also use throw "error_code".

Longstanding answered 16/4, 2015 at 10:53 Comment(1)
You edited your answer. I was asking for the second part but you answer it while I was posting. I am a beginner with promises. I learn the form (defer with resolve and reject) and I was using it in my project everywhere. Thanks a lot for pointing me that I could use directly $q or throw error.Banister
B
1

Thanks for your answer, I can see my error on the first code version. I think it's the q.all which perturbs me.

I read the deferred antipattern. It said that we don't have to create deferred objects for no reason.

The simple case is this :

 return Action1().then(function () {
     return $q.all([Action2(),Action3(), Action4()]);           
 });

But due to the if (data.condition) I can't do it. Is my second code the only way to do it? Am I in a case or I have to use defer?

It speaks about "promisification", but with Angular I don't know if it's a good thing (libs seem unmaintained).

Cheers,

Banister answered 16/4, 2015 at 11:17 Comment(3)
Yes, you should use deferreds for promisification only. Though in angular, the two most used async methods $http and $timeout already do return promises, so you rarely ever need it.Longstanding
In Angular 1.3, I saw they introduce a new syntax for the $q constructor. What do you think about it? Is it a good practise to use it ?Banister
A right, a promise constructor. Yes, it's good practise to use it instead of deferreds, it's the new standard for promises. But the "deferred antipattern" still is the same, maybe as the "promise constructor antipattern" then. Don't use either when the function you work with already return promises.Longstanding

© 2022 - 2024 — McMap. All rights reserved.