2

I'm really confused with my bit of code, which is an angularjs service. I tried to use Promise.all to concatenate the two promises that are part of the service, and to send the result to my controller. The thing is that the object returned by Promise.all is composed by the two same arrays. My code here, just to be clearer:

batchModule.service('BatchService', ['$http', '$q', '$log', 'MessageboxService', function ($http, $q, $log, MessageboxService) {

let deferred = $q.defer();

this.loadAll = () => {

    promise1 = () => {
        $http.get(_restApiPath + "/batch/?processtype=IMPORT_CUSTOMER")
        // loadLastFiveBatch('IMPORT_CUSTOMER')
            .then(function (response) {
                deferred.resolve(response.data);
                // datas.push(response1);
                // console.log(datas);
            }, function (error) {
                deferred.reject(error);
                $log.error(error);
            });
        return deferred.promise;
    };

    promise2 = () => {
        $http.get(_restApiPath + "/batch/?processtype=IMPORT_LAB_MARGIN")
        // loadLastFiveBatch('IMPORT_LAB_MARGIN')
            .then(function (response) {
                deferred.resolve(response.data);
                // datas.push(response2);
                // console.log(datas);
            }, function (error) {
                deferred.reject(error);
                $log.error(error);
            });
        return deferred.promise;
    };

    Promise.all([promise1(), promise2()])
    .then(values => {
        console.log(values);
    });

};
}]);

The console.log(values) return an object made of 2 equal arrays returned by the IMPORT_CUSTOMER request, when the second argument of the Promise.all is precisely a promise returned by the IMPORT_MARGIN request. I'have been working on it few hours today but I can't find any solution. I hope I was clear enough, my english is not great. Thank you for your answers :-)

Piotr___
  • 39
  • 1
  • 9
  • 2
    You only have a single global `deferred`, so it's kinda obvious why it can resolve to only one value. And of course, avoid the [deferred antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) in the first place! – Bergi Aug 16 '17 at 21:49

2 Answers2

1

Both your promises actually return the same $q.defer(); promise. So you need to drop the deferred anti-pattern (using $q.defer() instead of just return $http.get(..);) and the problem should pretty much solve itself.

So change your code to this:

batchModule.service('BatchService', ['$http', '$q', '$log', 'MessageboxService', function ($http, $q, $log, MessageboxService) {

    this.loadAll = () => {

        promise1 = () => {
            return $http.get(_restApiPath + "/batch/?processtype=IMPORT_CUSTOMER")
                .then(response => response.data, error => {
                    $log.error(error);
                    return $q.reject(error);
                });
        };

        promise2 = () => {
            return $http.get(_restApiPath + "/batch/?processtype=IMPORT_MARGIN")
                .then(response => response.data, error => {
                    $log.error(error);
                    return $q.reject(error);
                });
        };

        $q.all([promise1, promise2])
        .then(values => {
            console.log(values);
        });
    };
}]);
Nikolaj Dam Larsen
  • 5,455
  • 4
  • 32
  • 45
  • Be aware that `Promise.all` is not integrated with the AngularJS framework and its digest cycle. To avoid problems, **instead use [$q.all](https://docs.angularjs.org/api/ng/service/$q#all).** AngularJS modifies the normal JavaScript flow by providing its own event processing loop. This splits the JavaScript into classical and AngularJS execution context. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc. – georgeawg Aug 16 '17 at 22:14
  • Changed `Promise.all` to `$q.all`. Pretty much just copy-pasted that part blindly. :-) – Nikolaj Dam Larsen Aug 17 '17 at 04:48
  • 1
    I just edited my code! Thank you all for your explanations. My first question on stackoverflow was resolved in less than 10 min :-) – Piotr___ Aug 17 '17 at 05:16
1

Problem caused because you used single deferred for all of your promise. So that single that reference get resolved, it will resolved for further instances of your promise call. So rather use different deferred for each request. Still I don't preferred to use deferred anti-pattern. Rather use build in promise return by $http.get method.

Additionally you had Promise.all at the end of the function, this won't run angular digest cycle. Eventually if you are going to update any bindings from this function won't update bindings on UI. Consider chainging it to use $q.all

this.loadAll = () => {

    promise1 = () => {
        return $http.get(_restApiPath + "/batch/?processtype=IMPORT_CUSTOMER")
            .then(function (response) {
                return response.data;
            }, function (error) {
                $log.error(error);
                return $q.reject(error);
            }
        );
    };

    promise2 = () => {
        $http.get(_restApiPath + "/batch/?processtype=IMPORT_LAB_MARGIN")
        // loadLastFiveBatch('IMPORT_LAB_MARGIN')
            .then(function (response) {
                return response.data;
            }, function (error) {
                $log.error(error);
                return $q.reject(error);
            }
        );
    };
    //return is needed if any function is trying to chain `loadAll` function.
    return $q.all([promise1(), promise2()])
    .then(values => {
        console.log("promise1", values[0]);
        console.log("promise2", values[1]);
    });

};
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299