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;
});

2 Answers 2

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".

Sign up to request clarification or add additional context in comments.

1 Comment

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.
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,

3 Comments

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.
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 ?
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.