Is there an any method ordering when $q.all has multiple http call functions in Angularjs?

4.5k Views Asked by At

First of all, I am not good at angularjs.

While I've been studying about $q, I faced a weird problem.

When I use $q.all, I put $http in regular sequence expecting to get results in same order,

but what I get was random results.

See this and correct my stupidity.

    $q.all([
        HttpService.editItem(
            $scope.$parent.category_id,           //  category id
            Define.CAR_CAT,                         //  category url to request
            $scope.car_id,                           //  car_id wanna edit
            {car_name: inputValue.toUpperCase()}    //  data
        ),
        HttpService.getCarList(
            $scope.$parent.category_id,     //  category id
            Define.CAR_CAT                    //  category url to request
        )
    ]).then(function (results) {
        if (results[0].statusText === 'OK' && results[1].statusText === 'OK') {
            .....
    });

'HttpService' is a service of my app. It returns promise.

What I expected was

edit car name first, get car list later.

But results I got was get car list first, edit car name later.

And I'm using

return $q(function(resolve, reject){ });

instead of using

$q.defer();

.

.

.

.

and these are my HttpService part

function editItem(cat_id, cat_url, content_id, item_data) {
    return $q(function (resolve, reject) {
        $http({
            method: 'PUT',
            url: Define.TEST_URL + cat_id + cat_url + content_id,
            data: item_data
        }).then(function (response) {
            resolve(response);
        }, function (error) {
            reject(error);
        });
    });
}



function getCarList(cat_id, cat_url) {
    return $q(function (resolve, reject) {
        $http({
            method: 'GET',
            url: Define.TEST_URL + cat_id + cat_url
        }).then(function (response) {
            resolve(response);
        }, function (error) {
            reject(error);
        });
    });
}

and here is the getCarList response

{
    "error_msg": "",
    "error_num": 0,
    "statusText": "OK"
    "results": [
            {
            "car_id": "CAR0121",
                "car_name": "AUDI R8"
            },
            {
                "car_id": "CAR0122",
                "car_name": "AUDI A6"
            },
            {
                "car_id": "CAR0128",
                "car_name": "BENZ"
            },
            {
                "car_id": "CAR0130",
                "car_name": "PORCHE"
            },
    ]
}
3

There are 3 best solutions below

1
Icycool On BEST ANSWER

If you want the calls to be sequential, you'll need to call them by using promise chaining instead of $q.all

HttpService.editItem(
        $scope.$parent.category_id,             //  category id
        Define.CAR_CAT,                         //  category url to request
        $scope.car_id,                          //  car_id wanna edit
        {car_name: inputValue.toUpperCase()}    //  data
    )
    .then(function(result) {
        if (result.statusText === 'OK') {
            return HttpService.getCarList(
                $scope.$parent.category_id,     //  category id
                Define.CAR_CAT                  //  category url to request
            )
        }
        else {
            return $q.reject();
        }
    })
    .then(function (result) {
        if (result.statusText === 'OK') {
        .....
    });
5
Yury Tarabanko On

but what I get was random results.

$q.all will await for promises running concurrently. So there is no guarantee which request hits server first. But the order of responses will be kept.

If you want to make sure you read after write you have to wait for write response to respond it was ok

var editing = HttpService.editItem(
        $scope.$parent.category_id,           //  category id
        Define.CAR_CAT,                         //  category url to request
        $scope.car_id,                           //  car_id wanna edit
        {car_name: inputValue.toUpperCase()}    //  data
    )
 var reading = editing.then(function() {
    return HttpService.getCarList(
        $scope.$parent.category_id,     //  category id
        Define.CAR_CAT                    //  category url to request
    )
   })

//if you need both results
$q.all([editing, reading]).then(function(results) {

})
13
Maxim Shoustin On

Is there an method order in $q.all in Angularjs?

Yes, the Order is regards to Promises order you gave it to $q.all()

From ref: $q.all()

Returns a single promise that will be resolved with an array/hash of values, each value corresponding to the promise at the same index/key in the promises array/hash. If any of the promises is resolved with a rejection, this resulting promise will be rejected with the same rejection value.

Example 1 (list)

var  promises = [promise1(), promise2(), promise3()];

$q.all(promises).then((values) => {
    console.log(values[0]); // value promise1
    console.log(values[1]); // value promise2
    console.log(values[2]); // value promise3
});

Example 2 (map)

var  promises = {one: promise1(), two: promise2(), three: promise3()};

$q.all(promises).then((values) => {
    console.log(values.one); // value promise1
    console.log(values.two); // value promise2
    console.log(values.three); // value promise3
});

But results I got was get car list first, edit car name later.

I suggest you to create map approach and test what you get:

$q.all({edit:
    HttpService.editItem(
        $scope.$parent.category_id,           //  category id
        Define.CAR_CAT,                         //  category url to request
        $scope.car_id,                           //  car_id wanna edit
        {car_name: inputValue.toUpperCase()}    //  data
    ),
    getCar: HttpService.getCarList(
        $scope.$parent.category_id,     //  category id
        Define.CAR_CAT                    //  category url to request
    )
}).then(function (results) {
   // results.edit
   // results.getCar 
});

EDIT

demo Plunker using Map

demo Plunker using List