3

I have an array and i need to send values of array to webservice through http post request one by one . For the node.js , i'm using "async" package to do that for ex: async.eachSeries doing it well , how can i do that same thing for angular.js , my normal async code;

//this code sends all queries of array (maybe  5.000 request at same time , it is hard to process for webservice :=) ) at same time and wait for all responses. 
//it works but actually for me , responses should wait others at end of loop should work one by one 
//like async.eachSeries module!

    for (var i = 0; i < myArr.lenght; i++) {
        (function (i) {
                var data = {
                    "myQuery": myArr[i].query
                };
                $http.post("/myServiceUrl", data).success(function (result) {
                    console.log(result);
                });
        })(i);
}

Both Matt Way and Chris L answers Correct , you can investigate Chris's answer for understanding about async to sync functions in for loops.

2
  • Does the order matter? Commented Oct 17, 2015 at 0:54
  • 1
    you can use the async package in the browser with angular's $http. The only issue you'll have is if you want to update your $scope with your results then you may need to use $scope.$apply or $timeout (without the optional delay) Commented Oct 17, 2015 at 1:54

4 Answers 4

2

You can use $q to create a similar requirement by chaining promises together. For example:

var chain = $q.when();
angular.forEach(myArr, function(item){
    chain = chain.then(function(){
        var data = {
            myQuery: item.query
        };
        return $http.post('/myServiceUrl', data).success(function(result){
            console.log(result);
        });
    });
});

// the final chain object will resolve once all the posts have completed.
chain.then(function(){
    console.log('all done!');
});

Essentially you are just running the next promise once the previous one has completed. Emphasis here on the fact that each request will wait until the previous one has completed, as per your question.

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

10 Comments

$q is angular's promise library, and was in angular from the beginning. Promises are by far the correct way to use $http, not the convoluted answer you marked as correct. If you create a fiddle, we can help you.
@MattWay the problem with the q library comes when you are performing large sequential calculations and manipulating data in a sequential manner requiring error handling to alert user to provide more input, etc. It depends on your use case and your blanket statement is not entirely correct based on my attempts at implementation in a statistical calculation application
Your comment makes no sense? What does this question have to do with 'large sequential calculations'? Osman wanted to perform a chain of $http calls, and this answer does that using promises, which was the intention of $q. I am curious about your belief of problems with $q though, it would probably make a good question.
ps. @MattWay . I am still relatively new myself. I am having this discussion to learn from more experienced developers. Please don't interpret my conversation as "arguing" as much as it is prying into more experienced minds. It is tough to make this clear in text. Sincerely, Chris
Okay bro , i investigated and i am thinking to create a async module for angular now :P , it is very illustrative , i wish i can choose both answers as correct :)
|
1
function logResultFromWebService(value)
{
    $http.post("/myServiceUrl", value).success(console.log);
}

angular.forEach(myArray, logResultFromWebService);

Comments

1

If I understand your question correctly. You want to run a for loop in a synchronized manner such that the next iteration only occurs once the previous iteration is completed. For that, you can use a synchronized loop/callbacks. Especially if the order matters.

        var syncLoop = function (iterations, process, exit) {
            var index = 0,
                done = false,
                shouldExit = false;
            var loop = {
                next: function () {
                    if (done) {
                        if (shouldExit && exit) {
                            return exit(); // Exit if we're done
                        }
                    }
                    // If we're not finished
                    if (index < iterations) {
                        index++; // Increment our index
                        process(loop); // Run our process, pass in the loop
                        // Otherwise we're done
                    } else {
                        done = true; // Make sure we say we're done
                        if (exit) exit(); // Call the callback on exit
                    }
                },
                iteration: function () {
                    return index - 1; // Return the loop number we're on
                },
                break: function (end) {
                    done = true; // End the loop
                    shouldExit = end; // Passing end as true means we still call the exit callback
                }
            };
            console.log('running first time');
            loop.next();
            return loop;
        }

For your particular implementation:

    syncLoop(myArray.length, function (loop) {
        var index = loop.iteration();
        var data = {
            "myQuery": myArray[index].query
        };
        $http.post("/myServiceUrl", data).success(function (result) {
            console.log(result);
            loop.next();
        });
    }, function () {
        console.log('done');
    });

If you intend on doing something with the data once returned (such as perform calculations) you can do so with this method because you will return the data in a specified order.

I implemented something similar in a statistical calculation web app I built.

EDIT:

To illustrate the problem I had when using $q.when I have set up a fiddle. Hopefully this will help illustrate why I did this the way I did.

https://jsfiddle.net/chrislewispac/6atp3w8o/

Using the following code from Matt's answer:

var chain = $q.when(promise.getResult());
    angular.forEach(myArr, function (item) {
        chain = chain.then(function () {
            $rootScope.status = item;
            console.log(item);
        });
    });

    // the final chain object will resolve once all the posts have completed.
    chain.then(function () {
        console.log('all done!');
    });

And this fiddle is an example of my solution:

https://jsfiddle.net/chrislewispac/Lgwteone/3/

Compare the $q version to my version. View the console and imagine those being delivered to the user interface for user intervention in the process and/or performing statistical operations on the sequential returns.

You will see that it does not sequentially give the numbers 1,2,3,4 etc. either in the console or in the view in Matt's answer. It 'batches' the responses and then returns them. Therefore, if step 3 is not to be run depending on the response in step 2 there is not, at least in the answer provided, a way to break out or explicitly control the synchronous operation here. This presents a significant problem when attempting to perform sequential calculations and/or allow the user to control break points, etc.

Now, I am digging through both the $q libraries and the Q library to see if there is a more elegant solution for this problem. However, my solution does work as requested and is very explicit which allows me to place the function in a service and manipulate for certain use cases at my will because I completely understand what it is doing. For me, that is more important than using a library (at least at this stage in my development as a programmer and I am sure there are lots of other people at the same stage on StackOverflow as well).

6 Comments

I guess I misunderstood your question?
its okay , every request's reponses wait eachother with this code , thank you for your great help :) ,Moreover , this answer will be very useful for others .
While this answer technically works, it is not a good choice of solution.
Im sorry you seem so upset with my answer @MattWay . Perhaps if you give a fiddle, performing data driven calculations in a defined sequential orders with error handling and show it to us you could enlighten both of us instead of just saying "it works but its not good." This is a learning experience for everyone, CONSTRUCTIVE criticism is the entire point of participating here. :-)
I did provide a more correct answer. What you have written is basically a simplified custom version of what $q does for you anyway. Would you agree that reinventing the wheel may not be the best approach?
|
0

If the order doesn't matter in which they are sent

var items = [/* your array */];
var promises = [];
angular.forEach(items, function(value, key){
    var promise = $http.post("/myServiceUrl", { "myQuery": value.query });
    promises.push(promise);
});
return $q.all(promises);

1 Comment

I believe this will still send all requests simultaneously, and is not about order.

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.